ruby_protobuf 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. data/History.txt +3 -1
  2. data/bin/mk_parser +2 -0
  3. data/bin/rprotoc +1 -1
  4. data/lib/protobuf/compiler/compiler.rb +12 -12
  5. data/lib/protobuf/compiler/nodes.rb +140 -35
  6. data/lib/protobuf/compiler/proto.y +7 -4
  7. data/lib/protobuf/compiler/proto_parser.rb +170 -167
  8. data/lib/protobuf/compiler/template/rpc_bin.erb +1 -1
  9. data/lib/protobuf/compiler/template/rpc_client.erb +1 -1
  10. data/lib/protobuf/compiler/visitors.rb +168 -16
  11. data/lib/protobuf/message/enum.rb +3 -0
  12. data/lib/protobuf/message/field.rb +52 -37
  13. data/lib/protobuf/message/message.rb +37 -14
  14. data/lib/protobuf/message/protoable.rb +37 -0
  15. data/lib/ruby_protobuf.rb +1 -1
  16. data/test/addressbook.rb +36 -0
  17. data/test/check_unbuild.rb +1 -1
  18. data/test/collision.rb +18 -0
  19. data/test/data/types.bin +0 -0
  20. data/test/data/unk.png +0 -0
  21. data/test/ext_collision.rb +25 -0
  22. data/test/ext_range.rb +23 -0
  23. data/test/merge.rb +40 -0
  24. data/test/nested.rb +25 -0
  25. data/test/proto/addressbook.pb.rb +69 -0
  26. data/test/{addressbook.proto → proto/addressbook.proto} +1 -0
  27. data/test/proto/addressbook.rb +69 -0
  28. data/test/{addressbook_base.proto → proto/addressbook_base.proto} +0 -0
  29. data/test/{addressbook_ext.proto → proto/addressbook_ext.proto} +0 -0
  30. data/test/proto/bool_default.pb.rb +16 -0
  31. data/test/proto/bool_default.proto +3 -0
  32. data/test/proto/collision.proto +5 -0
  33. data/test/proto/ext_collision.proto +8 -0
  34. data/test/proto/ext_range.proto +7 -0
  35. data/test/proto/float_default.proto +2 -0
  36. data/test/proto/merge.proto +15 -0
  37. data/test/proto/nested.proto +7 -0
  38. data/test/{rpc.proto → proto/rpc.proto} +0 -0
  39. data/test/{types.proto → proto/types.proto} +0 -0
  40. data/test/test_compiler.rb +191 -12
  41. data/test/test_message.rb +86 -0
  42. data/test/test_standard_message.rb +8 -5
  43. data/test/test_types.rb +9 -8
  44. metadata +26 -13
  45. data/Manifest.txt +0 -62
  46. data/examples/addressbook.proto +0 -24
  47. data/examples/addressbook.rb +0 -30
  48. data/examples/reading_a_message.rb +0 -32
  49. data/examples/writing_a_message.rb +0 -46
@@ -17,6 +17,7 @@ message Person {
17
17
  }
18
18
 
19
19
  repeated PhoneNumber phone = 4;
20
+ optional uint32 age = 5 [default = 20];
20
21
 
21
22
  extensions 100 to 200;
22
23
  }
@@ -0,0 +1,69 @@
1
+ ### Generated by rprotoc. DO NOT EDIT!
2
+ ### <proto file: test/proto/addressbook.proto>
3
+ # package tutorial;
4
+ #
5
+ # message Person {
6
+ # required string name = 1;
7
+ # required int32 id = 2;
8
+ # optional string email = 3;
9
+ #
10
+ # enum PhoneType {
11
+ # MOBILE = 0;
12
+ # HOME = 1;
13
+ # WORK = 2;
14
+ # }
15
+ #
16
+ # message PhoneNumber {
17
+ # required string number = 1;
18
+ # optional PhoneType type = 2 [default = HOME];
19
+ # }
20
+ #
21
+ # repeated PhoneNumber phone = 4;
22
+ # optional uint32 age = 5 [default = 20];
23
+ #
24
+ # extensions 100 to 200;
25
+ # }
26
+ #
27
+ # extend Person {
28
+ # optional int32 age = 100;
29
+ # }
30
+ #
31
+ # message AddressBook {
32
+ # repeated Person person = 1;
33
+ # }
34
+
35
+ require 'protobuf/message/message'
36
+ require 'protobuf/message/enum'
37
+ require 'protobuf/message/service'
38
+ require 'protobuf/message/extend'
39
+
40
+ module Tutorial
41
+ class Person < ::Protobuf::Message
42
+ defined_in __FILE__
43
+ required :string, :name, 1
44
+ required :int32, :id, 2
45
+ optional :string, :email, 3
46
+ class PhoneType < ::Protobuf::Enum
47
+ defined_in __FILE__
48
+ MOBILE = 0
49
+ HOME = 1
50
+ WORK = 2
51
+ end
52
+ class PhoneNumber < ::Protobuf::Message
53
+ defined_in __FILE__
54
+ required :string, :number, 1
55
+ optional :PhoneType, :type, 2, :default => :HOME
56
+ end
57
+ repeated :PhoneNumber, :phone, 4
58
+ optional :uint32, :age, 5, :default => 20
59
+ extensions 100..200
60
+ end
61
+ class Person < ::Protobuf::Message
62
+ defined_in __FILE__
63
+ optional :int32, :age, 100, :extension => true
64
+ end
65
+ class AddressBook < ::Protobuf::Message
66
+ defined_in __FILE__
67
+ repeated :Person, :person, 1
68
+ end
69
+ end
@@ -0,0 +1,16 @@
1
+ ### Generated by rprotoc. DO NOT EDIT!
2
+ ### <proto file: test/proto/bool_default.proto>
3
+ # message BoolDefault {
4
+ # required bool enabled = 1 [default = true];
5
+ # }
6
+
7
+ require 'protobuf/message/message'
8
+ require 'protobuf/message/enum'
9
+ require 'protobuf/message/service'
10
+ require 'protobuf/message/extend'
11
+
12
+ class BoolDefault < ::Protobuf::Message
13
+ defined_in __FILE__
14
+ #required :bool, :enabled, 1, :default => true
15
+ optional :bool, :enabled, 1, :default => true
16
+ end
@@ -0,0 +1,3 @@
1
+ message BoolDefault {
2
+ required bool enabled = 1 [default = true];
3
+ }
@@ -0,0 +1,5 @@
1
+ message CollisionTest {
2
+ optional string a = 1;
3
+ optional string b = 1;
4
+ }
5
+
@@ -0,0 +1,8 @@
1
+ message ExtCollisionTest {
2
+ extensions 1 to 10;
3
+ }
4
+
5
+ message ExtCollisionTest {
6
+ optional string a = 1;
7
+ optional string b = 1;
8
+ }
@@ -0,0 +1,7 @@
1
+ message ExtCollisionTest {
2
+ extensions 1 to 10;
3
+ }
4
+
5
+ extend ExtCollisionTest {
6
+ optional string a = 11;
7
+ }
@@ -0,0 +1,2 @@
1
+ message M { optional float f = 1 [default = 4.2]; }
2
+
@@ -0,0 +1,15 @@
1
+ package test;
2
+
3
+ message MergeMessage {
4
+ message InnerMessage1 {
5
+ required string name = 1;
6
+ }
7
+ message InnerMessage2 {
8
+ required string name = 1;
9
+ repeated InnerMessage1 repeate_message = 2;
10
+ }
11
+
12
+ required string name = 1;
13
+ repeated InnerMessage1 repeate_message = 2;
14
+ required InnerMessage2 require_message = 3;
15
+ }
@@ -0,0 +1,7 @@
1
+ message Foo {
2
+ message Bar {
3
+ }
4
+ }
5
+ message Baaz {
6
+ optional Foo.Bar x = 1;
7
+ }
File without changes
File without changes
@@ -3,8 +3,61 @@ require 'test/unit'
3
3
  require 'protobuf/compiler/compiler'
4
4
 
5
5
  class CompilerTest < Test::Unit::TestCase
6
+ # Issue 12: Parse error on float default value
7
+ def test_compile_float_default
8
+ assert_compile_proto <<-eos, 'test/proto/float_default.proto'
9
+ ### Generated by rprotoc. DO NOT EDIT!
10
+ ### <proto file: test/proto/float_default.proto>
11
+ # message M { optional float f = 1 [default = 4.2]; }
12
+ #
13
+
14
+ require 'protobuf/message/message'
15
+ require 'protobuf/message/enum'
16
+ require 'protobuf/message/service'
17
+ require 'protobuf/message/extend'
18
+
19
+ class M < ::Protobuf::Message
20
+ defined_in __FILE__
21
+ optional :float, :f, 1, :default => 4.2
22
+ end
23
+ eos
24
+ end
25
+
6
26
  def test_create_message
7
- assert_equal <<-eos.gsub(/^\s*\n/, '').strip, Protobuf::Compiler.new.create_message('test/addressbook.proto', '.', '.', false).gsub(/^\s*\n/, '').strip
27
+ assert_compile_proto <<-eos, 'test/proto/addressbook.proto'
28
+ ### Generated by rprotoc. DO NOT EDIT!
29
+ ### <proto file: test/proto/addressbook.proto>
30
+ # package tutorial;
31
+ #
32
+ # message Person {
33
+ # required string name = 1;
34
+ # required int32 id = 2;
35
+ # optional string email = 3;
36
+ #
37
+ # enum PhoneType {
38
+ # MOBILE = 0;
39
+ # HOME = 1;
40
+ # WORK = 2;
41
+ # }
42
+ #
43
+ # message PhoneNumber {
44
+ # required string number = 1;
45
+ # optional PhoneType type = 2 [default = HOME];
46
+ # }
47
+ #
48
+ # repeated PhoneNumber phone = 4;
49
+ # optional uint32 age = 5 [default = 20];
50
+ #
51
+ # extensions 100 to 200;
52
+ # }
53
+ #
54
+ # extend Person {
55
+ # optional int32 age = 100;
56
+ # }
57
+ #
58
+ # message AddressBook {
59
+ # repeated Person person = 1;
60
+ # }
8
61
  require 'protobuf/message/message'
9
62
  require 'protobuf/message/enum'
10
63
  require 'protobuf/message/service'
@@ -13,44 +66,88 @@ require 'protobuf/message/extend'
13
66
  module Tutorial
14
67
 
15
68
  class Person < ::Protobuf::Message
69
+ defined_in __FILE__
16
70
  required :string, :name, 1
17
71
  required :int32, :id, 2
18
72
  optional :string, :email, 3
19
73
 
20
74
  class PhoneType < ::Protobuf::Enum
75
+ defined_in __FILE__
21
76
  MOBILE = 0
22
77
  HOME = 1
23
78
  WORK = 2
24
79
  end
25
80
 
26
81
  class PhoneNumber < ::Protobuf::Message
82
+ defined_in __FILE__
27
83
  required :string, :number, 1
28
84
  optional :PhoneType, :type, 2, :default => :HOME
29
85
  end
30
86
 
31
87
  repeated :PhoneNumber, :phone, 4
88
+ optional :uint32, :age, 5, :default => 20
32
89
 
33
90
  extensions 100..200
34
91
  end
35
92
 
36
93
  class Person < ::Protobuf::Message
94
+ defined_in __FILE__
37
95
  optional :int32, :age, 100, :extension => true
38
96
  end
39
97
 
40
98
  class AddressBook < ::Protobuf::Message
99
+ defined_in __FILE__
41
100
  repeated :Person, :person, 1
42
101
  end
43
102
  end
44
103
  eos
45
104
  end
46
105
 
106
+ def test_create_nested_message
107
+ assert_compile_proto <<-eos, 'test/proto/nested.proto'
108
+ ### Generated by rprotoc. DO NOT EDIT!
109
+ ### <proto file: test/proto/nested.proto>
110
+ # message Foo {
111
+ # message Bar {
112
+ # }
113
+ # }
114
+ # message Baaz {
115
+ # optional Foo.Bar x = 1;
116
+ # }
117
+ require 'protobuf/message/message'
118
+ require 'protobuf/message/enum'
119
+ require 'protobuf/message/service'
120
+ require 'protobuf/message/extend'
121
+
122
+ class Foo < ::Protobuf::Message
123
+ defined_in __FILE__
124
+ class Bar < ::Protobuf::Message
125
+ defined_in __FILE__
126
+ end
127
+ end
128
+
129
+ class Baaz < ::Protobuf::Message
130
+ defined_in __FILE__
131
+ optional :'Foo::Bar', :x, 1
132
+ end
133
+ eos
134
+ end
135
+
136
+ def test_nested_message
137
+ Protobuf::Visitor::CreateMessageVisitor.instance_eval {remove_const :Baaz}
138
+ file_contents = Protobuf::Compiler.new.create_message('test/proto/nested.proto', '.', '.', false)
139
+ assert_nothing_raised {eval file_contents}
140
+ assert_raise(TypeError) {Baaz.new.x = 1}
141
+ assert_nothing_raised {Baaz.new.x = Foo::Bar.new}
142
+ end
143
+
47
144
  def test_create_rpc
48
- file_contents = Protobuf::Compiler.new.create_rpc('test/rpc.proto', '.', '.', false)
145
+ file_contents = Protobuf::Compiler.new.create_rpc('test/proto/rpc.proto', '.', '.', false)
49
146
 
50
- assert_source <<-eos, file_contents['./address_book_service.rb']
147
+ assert_source <<-eos, file_contents['./test/proto/address_book_service.rb']
51
148
  require 'protobuf/rpc/server'
52
149
  require 'protobuf/rpc/handler'
53
- require 'test/rpc'
150
+ require 'test/proto/rpc.pb'
54
151
 
55
152
  class Tutorial::SearchHandler < Protobuf::Rpc::Handler
56
153
  request Tutorial::Person
@@ -80,17 +177,17 @@ class Tutorial::AddressBookService < Protobuf::Rpc::Server
80
177
  end
81
178
  eos
82
179
 
83
- assert_source <<-eos, file_contents['./start_address_book_service']
84
- #!/usr/bin/ruby
180
+ assert_source <<-eos, file_contents['./test/proto/start_address_book_service']
181
+ #!/usr/bin/env ruby
85
182
  require 'address_book_service'
86
183
 
87
184
  Tutorial::AddressBookService.new(:port => 9999).start
88
185
  eos
89
186
 
90
- assert_source <<-eos, file_contents['./client_search.rb']
91
- #!/usr/bin/ruby
187
+ assert_source <<-eos, file_contents['./test/proto/client_search.rb']
188
+ #!/usr/bin/env ruby
92
189
  require 'protobuf/rpc/client'
93
- require 'test/rpc'
190
+ require 'test/proto/rpc.pb'
94
191
 
95
192
  # build request
96
193
  request = Tutorial::Person.new
@@ -107,10 +204,10 @@ Protobuf::Rpc::Client.new('localhost', 9999).call :search, request, response
107
204
  puts response
108
205
  eos
109
206
 
110
- assert_source <<-eos, file_contents['./client_add.rb']
111
- #!/usr/bin/ruby
207
+ assert_source <<-eos, file_contents['./test/proto/client_add.rb']
208
+ #!/usr/bin/env ruby
112
209
  require 'protobuf/rpc/client'
113
- require 'test/rpc'
210
+ require 'test/proto/rpc.pb'
114
211
 
115
212
  # build request
116
213
  request = Tutorial::Person.new
@@ -128,6 +225,88 @@ puts response
128
225
  eos
129
226
  end
130
227
 
228
+ def test_create_descriptor
229
+ proto_path = 'test/proto/addressbook.proto'
230
+ visitor = Protobuf::Visitor::CreateDescriptorVisitor.new proto_path
231
+ File.open proto_path, 'r' do |file|
232
+ visitor.visit Protobuf::ProtoParser.new.parse(file)
233
+ end
234
+ file_descriptor = visitor.file_descriptor
235
+ assert_equal proto_path, file_descriptor.name
236
+ assert_equal 'tutorial', file_descriptor.package
237
+
238
+ person_descriptor = file_descriptor.message_type[0]
239
+ assert_equal 'Person', person_descriptor.name
240
+ assert_equal [:name, :id, :email, :phone, :age].size, person_descriptor.field.size
241
+
242
+ name_field_descriptor = person_descriptor.field.find {|d| d.name == 'name'}
243
+ assert_equal 1, name_field_descriptor.number
244
+ assert_equal Google::Protobuf::FieldDescriptorProto::Type::TYPE_STRING, name_field_descriptor.type
245
+ assert_equal Google::Protobuf::FieldDescriptorProto::Label::LABEL_REQUIRED, name_field_descriptor.label
246
+ assert_equal 'string', name_field_descriptor.type_name
247
+
248
+ phone_field_descriptor = person_descriptor.field.find {|d| d.name == 'phone'}
249
+ assert_equal 4, phone_field_descriptor.number
250
+ assert_equal 0, phone_field_descriptor.type #TODO: is this right?
251
+ assert_equal Google::Protobuf::FieldDescriptorProto::Label::LABEL_REPEATED, phone_field_descriptor.label
252
+ assert_equal 'PhoneNumber', phone_field_descriptor.type_name
253
+
254
+ age_field_descriptor = person_descriptor.field.find {|d| d.name == 'age'}
255
+ assert_equal 5, age_field_descriptor.number
256
+ assert_equal Google::Protobuf::FieldDescriptorProto::Type::TYPE_UINT32, age_field_descriptor.type
257
+ assert_equal Google::Protobuf::FieldDescriptorProto::Label::LABEL_OPTIONAL, age_field_descriptor.label
258
+ assert_equal 'uint32', age_field_descriptor.type_name
259
+ assert_equal '20', age_field_descriptor.default_value
260
+
261
+ phone_type_descriptor = person_descriptor.enum_type.first
262
+ assert_equal 'PhoneType', phone_type_descriptor.name
263
+ assert_equal 3, phone_type_descriptor.value.size
264
+
265
+ phone_type_home_descriptor = phone_type_descriptor.value.find {|d| d.name == 'HOME'}
266
+ assert_equal 'HOME', phone_type_home_descriptor.name
267
+ assert_equal 1, phone_type_home_descriptor.number
268
+
269
+ extensions_descriptor = person_descriptor.extension_range.first
270
+ assert_equal 100, extensions_descriptor.start
271
+ assert_equal 200, extensions_descriptor.end
272
+
273
+ phone_number_descriptor = person_descriptor.nested_type.first
274
+ assert_equal 'PhoneNumber', phone_number_descriptor.name
275
+ assert_equal [:number, :type].size, phone_number_descriptor.field.size
276
+
277
+ #TODO: test extend
278
+ #extend_person_descriptor = ??
279
+ #assert_equal extend_person_descriptor
280
+
281
+ addressbook_descriptor = file_descriptor.message_type[1]
282
+ assert_equal 'AddressBook', addressbook_descriptor.name
283
+ end
284
+
285
+ def test_collision
286
+ assert_raise Protobuf::Message::TagCollisionError do require 'test/collision' end
287
+ assert_raise Protobuf::Message::TagCollisionError do
288
+ Protobuf::Compiler.new.create_message('test/proto/collision.proto', '.', '.', false)
289
+ end
290
+ end
291
+
292
+ def test_ext_collision
293
+ assert_raise Protobuf::Message::TagCollisionError do require 'test/ext_collision' end
294
+ assert_raise Protobuf::Message::TagCollisionError do
295
+ Protobuf::Compiler.new.create_message('test/proto/ext_collision.proto', '.', '.', false)
296
+ end
297
+ end
298
+
299
+ def test_ext_range
300
+ assert_raise RangeError do require 'test/ext_range' end
301
+ assert_raise RangeError do
302
+ Protobuf::Compiler.new.create_message('test/proto/ext_range.proto', '.', '.', false)
303
+ end
304
+ end
305
+
306
+ def assert_compile_proto(ideal, filename)
307
+ assert_equal ideal.gsub(/^\s*\n/, '').strip, Protobuf::Compiler.new.create_message(filename, '.', '.', false).gsub(/^\s*\n/, '').strip
308
+ end
309
+
131
310
  def assert_source(ideal, real)
132
311
  assert_equal ideal.strip.gsub(/^\s*\n/, '').gsub(/\s+\n/, "\n"), real.strip.gsub(/^\s*\n/, '').gsub(/\s+\n/, "\n")
133
312
  end
@@ -1,8 +1,18 @@
1
1
  require 'protobuf/message/message'
2
2
  require 'test/addressbook'
3
+ require 'test/merge'
3
4
  require 'test/unit'
4
5
 
5
6
  class MessageTest < Test::Unit::TestCase
7
+ def test_equality
8
+ person1 = Tutorial::Person.new :name => 'ando'
9
+ person2 = Tutorial::Person.new :name => 'ando'
10
+ person3 = Tutorial::Person.new :name => 'Ando'
11
+ assert person1 == person2
12
+ assert person1 != person3
13
+ assert person1 != 'ando'
14
+ end
15
+
6
16
  def test_bracketed_access
7
17
  person = Tutorial::Person.new
8
18
  name_tag = 1
@@ -17,4 +27,80 @@ class MessageTest < Test::Unit::TestCase
17
27
  assert_equal 200, person[:id]
18
28
  assert_equal 200, person['id']
19
29
  end
30
+
31
+ def test_initialize_with_hash
32
+ person = Tutorial::Person.new :name => 'Jiro', :id => 300, :email => 'jiro@ema.il'
33
+ assert_equal 'Jiro', person.name
34
+ assert_equal 300, person.id
35
+ assert_equal 'jiro@ema.il', person.email
36
+ end
37
+
38
+ def test_defined_filenames
39
+ assert Tutorial::Person.defined_filenames
40
+ assert_equal 1, Tutorial::Person.defined_filenames.size
41
+ assert Tutorial::Person.defined_filenames.first =~ %r{/.*/test/addressbook\.rb}
42
+ end
43
+
44
+ def test_proto_filenames
45
+ assert Tutorial::Person.proto_filenames
46
+ assert_equal 1, Tutorial::Person.proto_filenames.size
47
+ assert_equal 'test/addressbook.proto', Tutorial::Person.proto_filenames.first
48
+ end
49
+
50
+ def test_proto_contents
51
+ assert_equal <<-eos.strip, Tutorial::Person.proto_contents.values.first.strip
52
+ package tutorial;
53
+
54
+ message Person {
55
+ required string name = 1;
56
+ required int32 id = 2;
57
+ optional string email = 3;
58
+
59
+ enum PhoneType {
60
+ MOBILE = 0;
61
+ HOME = 1;
62
+ WORK = 2;
63
+ }
64
+
65
+ message PhoneNumber {
66
+ required string number = 1;
67
+ optional PhoneType type = 2 [default = HOME];
68
+ }
69
+
70
+ repeated PhoneNumber phone = 4;
71
+
72
+ extensions 100 to 200;
73
+ }
74
+
75
+ extend Person {
76
+ optional int32 age = 100;
77
+ }
78
+
79
+ message AddressBook {
80
+ repeated Person person = 1;
81
+ }
82
+ eos
83
+ end
84
+
85
+ def test_merge_field
86
+ inner_message1_2 = Test::MergeMessage::InnerMessage2.new(:name => 'name12')
87
+ inner_message1_2.repeate_message << Test::MergeMessage::InnerMessage1.new(:name => 'name121')
88
+ message1 = Test::MergeMessage.new :name => 'name1', :require_message => inner_message1_2
89
+ message1.repeate_message << Test::MergeMessage::InnerMessage1.new(:name => 'name11')
90
+
91
+ inner_message2_2 = Test::MergeMessage::InnerMessage2.new(:name => 'name22')
92
+ inner_message2_2.repeate_message << Test::MergeMessage::InnerMessage1.new(:name => 'name221')
93
+ message2 = Test::MergeMessage.new :name => 'name2', :require_message => inner_message2_2
94
+ message2.repeate_message << Test::MergeMessage::InnerMessage1.new(:name => 'name21')
95
+
96
+ message1.merge_from message2
97
+ assert_equal 'name2', message1.name
98
+ assert_equal 2, message1.repeate_message.size
99
+ assert_equal 'name11', message1.repeate_message[0].name
100
+ assert_equal 'name21', message1.repeate_message[1].name
101
+ assert_equal 'name22', message1.require_message.name
102
+ assert_equal 2, message1.require_message.repeate_message.size
103
+ assert_equal 'name121', message1.require_message.repeate_message[0].name
104
+ assert_equal 'name221', message1.require_message.repeate_message[1].name
105
+ end
20
106
  end