Selaa lähdekoodia

Fix Ruby module name generation when the ruby_package option is used (again) (#5794)

* Revert "Revert "Fix Ruby module name generation when the ruby_package option is used (#5735)""

This reverts commit bb211e851ec2158e479784bd68784784bf6594dc.

* add new files to Makefile.am
Joe Bolinger 6 vuotta sitten
vanhempi
commit
ae85b457d2

+ 1 - 1
ruby/tests/test_ruby_package.proto

@@ -2,6 +2,6 @@ syntax = "proto3";
 
 package foo_bar;
 
-option ruby_package = "A.B";
+option ruby_package = "A::B";
 
 message TestRubyPackageMessage {}

+ 1 - 1
ruby/tests/test_ruby_package_proto2.proto

@@ -2,6 +2,6 @@ syntax = "proto2";
 
 package foo_bar_proto2;
 
-option ruby_package = "A.B.Proto2";
+option ruby_package = "A::B::Proto2";
 
 message TestRubyPackageMessage {}

+ 8 - 2
src/Makefile.am

@@ -554,8 +554,14 @@ EXTRA_DIST =                                                   \
   google/protobuf/util/package_info.h                          \
   google/protobuf/compiler/ruby/ruby_generated_code.proto      \
   google/protobuf/compiler/ruby/ruby_generated_code_pb.rb      \
-  google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto \
-  google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb \
+  google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto         \
+  google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb         \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto        \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy_pb.rb \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_pb.rb        \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_implicit.proto        \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_implicit_pb.rb        \
   google/protobuf/compiler/package_info.h                      \
   google/protobuf/compiler/zip_output_unittest.sh              \
   libprotobuf-lite.map                                         \

+ 9 - 0
src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto

@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+package one.two.a_three;
+
+option ruby_package = "A::B::C";
+
+message Four {
+  string a_string = 1;
+}

+ 9 - 0
src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto

@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+package one.two.a_three.and;
+
+option ruby_package = "AA.BB.CC";
+
+message Four {
+  string another_string = 1;
+}

+ 20 - 0
src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy_pb.rb

@@ -0,0 +1,20 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: ruby_generated_pkg_explicit_legacy.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_file("ruby_generated_pkg_explicit_legacy.proto", :syntax => :proto3) do
+    add_message "one.two.a_three.and.Four" do
+      optional :another_string, :string, 1
+    end
+  end
+end
+
+module AA
+  module BB
+    module CC
+      Four = Google::Protobuf::DescriptorPool.generated_pool.lookup("one.two.a_three.and.Four").msgclass
+    end
+  end
+end

+ 20 - 0
src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_pb.rb

@@ -0,0 +1,20 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: ruby_generated_pkg_explicit.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_file("ruby_generated_pkg_explicit.proto", :syntax => :proto3) do
+    add_message "one.two.a_three.Four" do
+      optional :a_string, :string, 1
+    end
+  end
+end
+
+module A
+  module B
+    module C
+      Four = Google::Protobuf::DescriptorPool.generated_pool.lookup("one.two.a_three.Four").msgclass
+    end
+  end
+end

+ 7 - 0
src/google/protobuf/compiler/ruby/ruby_generated_pkg_implicit.proto

@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+package one.two.a_three;
+
+message Four {
+  string a_string = 1;
+}

+ 20 - 0
src/google/protobuf/compiler/ruby/ruby_generated_pkg_implicit_pb.rb

@@ -0,0 +1,20 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: ruby_generated_pkg_implicit.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_file("ruby_generated_pkg_implicit.proto", :syntax => :proto3) do
+    add_message "one.two.a_three.Four" do
+      optional :a_string, :string, 1
+    end
+  end
+end
+
+module One
+  module Two
+    module AThree
+      Four = Google::Protobuf::DescriptorPool.generated_pool.lookup("one.two.a_three.Four").msgclass
+    end
+  end
+end

+ 22 - 5
src/google/protobuf/compiler/ruby/ruby_generator.cc

@@ -416,26 +416,43 @@ int GeneratePackageModules(
     const FileDescriptor* file,
     google::protobuf::io::Printer* printer) {
   int levels = 0;
-  bool need_change_to_module;
+  bool need_change_to_module = true;
   std::string package_name;
 
+  // Determine the name to use in either format:
+  //   proto package:         one.two.three
+  //   option ruby_package:   One::Two::Three
   if (file->options().has_ruby_package()) {
     package_name = file->options().ruby_package();
-    need_change_to_module = false;
+
+    // If :: is in the package use the Ruby formated name as-is
+    //    -> A::B::C
+    // otherwise, use the dot seperator
+    //    -> A.B.C
+    if (package_name.find("::") != std::string::npos) {
+      need_change_to_module = false;
+    } else {
+      GOOGLE_LOG(WARNING) << "ruby_package option should be in the form of:"
+                          << " 'A::B::C' and not 'A.B.C'";
+    }
   } else {
     package_name = file->package();
-    need_change_to_module = true;
   }
 
+  // Use the appropriate delimter
+  string delimiter = need_change_to_module ? "." : "::";
+  int delimiter_size = need_change_to_module ? 1 : 2;
+
+  // Extract each module name and indent
   while (!package_name.empty()) {
-    size_t dot_index = package_name.find(".");
+    size_t dot_index = package_name.find(delimiter);
     string component;
     if (dot_index == string::npos) {
       component = package_name;
       package_name = "";
     } else {
       component = package_name.substr(0, dot_index);
-      package_name = package_name.substr(dot_index + 1);
+      package_name = package_name.substr(dot_index + delimiter_size);
     }
     if (need_change_to_module) {
       component = PackageToModule(component);

+ 22 - 46
src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc

@@ -29,6 +29,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <memory>
+#include <list>
 
 #include <google/protobuf/compiler/ruby/ruby_generator.h>
 #include <google/protobuf/compiler/command_line_interface.h>
@@ -56,7 +57,7 @@ string FindRubyTestDir() {
 // Some day, we may integrate build systems between protoc and the language
 // extensions to the point where we can do this test in a more automated way.
 
-TEST(RubyGeneratorTest, Proto3GeneratorTest) {
+void RubyTest(string proto_file) {
   string ruby_tests = FindRubyTestDir();
 
   google::protobuf::compiler::CommandLineInterface cli;
@@ -68,22 +69,23 @@ TEST(RubyGeneratorTest, Proto3GeneratorTest) {
   // Copy generated_code.proto to the temporary test directory.
   string test_input;
   GOOGLE_CHECK_OK(File::GetContents(
-      ruby_tests + "/ruby_generated_code.proto",
+      ruby_tests + proto_file + ".proto",
       &test_input,
       true));
   GOOGLE_CHECK_OK(File::SetContents(
-      TestTempDir() + "/ruby_generated_code.proto",
+      TestTempDir() + proto_file + ".proto",
       test_input,
       true));
 
   // Invoke the proto compiler (we will be inside TestTempDir() at this point).
   string ruby_out = "--ruby_out=" + TestTempDir();
   string proto_path = "--proto_path=" + TestTempDir();
+  string proto_target = TestTempDir() + proto_file + ".proto";
   const char* argv[] = {
     "protoc",
     ruby_out.c_str(),
     proto_path.c_str(),
-    "ruby_generated_code.proto",
+    proto_target.c_str(),
   };
 
   EXPECT_EQ(0, cli.Run(4, argv));
@@ -91,61 +93,35 @@ TEST(RubyGeneratorTest, Proto3GeneratorTest) {
   // Load the generated output and compare to the expected result.
   string output;
   GOOGLE_CHECK_OK(File::GetContentsAsText(
-      TestTempDir() + "/ruby_generated_code_pb.rb",
+      TestTempDir() + proto_file + "_pb.rb",
       &output,
       true));
   string expected_output;
   GOOGLE_CHECK_OK(File::GetContentsAsText(
-      ruby_tests + "/ruby_generated_code_pb.rb",
+      ruby_tests + proto_file + "_pb.rb",
       &expected_output,
       true));
   EXPECT_EQ(expected_output, output);
 }
 
-TEST(RubyGeneratorTest, Proto2GeneratorTest) {
-  string ruby_tests = FindRubyTestDir();
-
-  google::protobuf::compiler::CommandLineInterface cli;
-  cli.SetInputsAreProtoPathRelative(true);
-
-  ruby::Generator ruby_generator;
-  cli.RegisterGenerator("--ruby_out", &ruby_generator, "");
+TEST(RubyGeneratorTest, Proto3GeneratorTest) {
+  RubyTest("/ruby_generated_code");
+}
 
-  // Copy generated_code.proto to the temporary test directory.
-  string test_input;
-  GOOGLE_CHECK_OK(File::GetContents(
-      ruby_tests + "/ruby_generated_code_proto2.proto",
-      &test_input,
-      true));
-  GOOGLE_CHECK_OK(File::SetContents(
-      TestTempDir() + "/ruby_generated_code_proto2.proto",
-      test_input,
-      true));
+TEST(RubyGeneratorTest, Proto2GeneratorTest) {
+    RubyTest("/ruby_generated_code_proto2");
+}
 
-  // Invoke the proto compiler (we will be inside TestTempDir() at this point).
-  string ruby_out = "--ruby_out=" + TestTempDir();
-  string proto_path = "--proto_path=" + TestTempDir();
-  const char* argv[] = {
-    "protoc",
-    ruby_out.c_str(),
-    proto_path.c_str(),
-    "ruby_generated_code_proto2.proto",
-  };
+TEST(RubyGeneratorTest, Proto3ImplicitPackageTest) {
+    RubyTest("/ruby_generated_pkg_implicit");
+}
 
-  EXPECT_EQ(0, cli.Run(4, argv));
+TEST(RubyGeneratorTest, Proto3ExplictPackageTest) {
+    RubyTest("/ruby_generated_pkg_explicit");
+}
 
-  // Load the generated output and compare to the expected result.
-  string output;
-  GOOGLE_CHECK_OK(File::GetContents(
-      TestTempDir() + "/ruby_generated_code_proto2_pb.rb",
-      &output,
-      true));
-  string expected_output;
-  GOOGLE_CHECK_OK(File::GetContents(
-      ruby_tests + "/ruby_generated_code_proto2_pb.rb",
-      &expected_output,
-      true));
-  EXPECT_EQ(expected_output, output);
+TEST(RubyGeneratorTest, Proto3ExplictLegacyPackageTest) {
+    RubyTest("/ruby_generated_pkg_explicit_legacy");
 }
 
 }  // namespace