diff --git a/dat/code_generator_request_import.dat b/dat/code_generator_request_import.dat new file mode 100644 index 0000000..10d6f62 --- /dev/null +++ b/dat/code_generator_request_import.dat @@ -0,0 +1,5 @@ + +bookshelf.protozb +bookshelf.proto importingaddressbook.proto"1 + BookShelf$ +books ( 2.tutorial.AddressBook \ No newline at end of file diff --git a/lib/beefcake.rb b/lib/beefcake.rb index 2083778..22707b5 100644 --- a/lib/beefcake.rb +++ b/lib/beefcake.rb @@ -272,7 +272,15 @@ def to_hash __beefcake_fields__.values.inject({}) do |h, fld| value = self[fld.name] unless value.nil? - h[fld.name] = value + case value + when Array + next if value.empty? + h[fld.name] = value.map {|val| val.is_a?(Message) ? val.to_hash : val} + when Message + h[fld.name] = value.to_hash + else + h[fld.name] = value + end end h end diff --git a/lib/beefcake/generator.rb b/lib/beefcake/generator.rb index 9e2ff29..c370adb 100644 --- a/lib/beefcake/generator.rb +++ b/lib/beefcake/generator.rb @@ -109,8 +109,10 @@ class FileDescriptorProto optional :name, :string, 1 # file name, relative to root of source tree optional :package, :string, 2 # e.g. "foo", "foo.bar", etc. - repeated :message_type, DescriptorProto, 4; - repeated :enum_type, EnumDescriptorProto, 5; + repeated :dependency, :string, 3 + + repeated :message_type, DescriptorProto, 4 + repeated :enum_type, EnumDescriptorProto, 5 end @@ -146,8 +148,9 @@ def self.compile(ns, req) g.compile(ns, file) g.c.rewind + # Change the filename to be relative to -I CodeGeneratorResponse::File.new( - :name => File.basename(file.name, ".proto") + ".pb.rb", + :name => file.name.gsub(".proto", ".pb.rb"), :content => g.c.read ) end @@ -239,7 +242,7 @@ def field!(pkg, f) end t = t.gsub(/^\.*/, "") # Remove leading `.`s - t.gsub(".", "::") # Convert to Ruby namespacing syntax + t.split(".").map { |e| e[0].capitalize + e[1..-1] }.join("::") # Convert to Ruby namespacing syntax else ":#{name_for(f, T, f.type)}" end @@ -273,7 +276,13 @@ def compile(ns, file) puts "require \"beefcake\"" puts + # Use the package as a namespace, converting under_scores to CamelCase for better Ruby style + ns += (file.package || "").split(/\W+/).map{ |e| e.split('_').map(&:capitalize).join('') } ns!(ns) do + Array(file.dependency).each do |df| + puts "require \"#{df.gsub(".proto", ".pb")}\"" + end + Array(file.enum_type).each do |et| enum!(et) end diff --git a/test/generator_test.rb b/test/generator_test.rb index ecccd53..553fe87 100644 --- a/test/generator_test.rb +++ b/test/generator_test.rb @@ -33,6 +33,28 @@ def test_generate_two_level_namespace assert_match(/module Top\s*\n\s*module Bottom/m, @res.file.first.content) end + def test_generate_package_namespace + @req.proto_file.first.package = "middle.bottom_level" + @res = Beefcake::Generator.compile(["Top"], @req) + assert_match(/module Top\s*\n\s*module Middle\s*\n\s*module BottomLevel/m, @res.file.first.content) + end + + def test_generate_import + # Load up the generator request for the addressbook.proto example + dat = File.dirname(__FILE__) + "/../dat/code_generator_request_import.dat" + mock_request = File.read(dat) + @req = CodeGeneratorRequest.decode(mock_request) + @res = Beefcake::Generator.compile([], @req) + assert_equal(CodeGeneratorResponse, @res.class) + assert_match(/require "addressbook.pb"/m, @res.file.first.content) + end + + def test_generate_retain_path + @req.proto_file.first.name = "proto/addressbook.proto" + @res = Beefcake::Generator.compile([], @req) + assert_equal("proto/addressbook.pb.rb", @res.file.first.name) + end + # Covers the regression of encoding a CodeGeneratorResponse under 1.9.2-p136 raising # Encoding::CompatibilityError: incompatible character encodings: ASCII-8BIT and US-ASCII def test_encode_decode_generated_response diff --git a/test/message_test.rb b/test/message_test.rb index 295c11e..53b8aed 100644 --- a/test/message_test.rb +++ b/test/message_test.rb @@ -433,6 +433,12 @@ def test_bool_to_hash assert_equal false_expectation, false_message.to_hash end + def test_nested_to_hash + msg = CompositeMessage.new(:encodable => SimpleMessage.new(:a => 1)) + exp = { :encodable => { :a => 1 } } + assert_equal(exp, msg.to_hash) + end + def test_fields_named_fields contents = %w{fields named fields} msg = FieldsMessage.new fields: contents