ruby_protobuf 0.3.2 → 0.3.3

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 (39) hide show
  1. data/History.txt +7 -2
  2. data/Manifest.txt +74 -0
  3. data/README.txt +1 -1
  4. data/Rakefile +5 -5
  5. data/bin/rprotoc +25 -10
  6. data/{test/proto → examples}/addressbook.pb.rb +1 -14
  7. data/examples/addressbook.proto +24 -0
  8. data/examples/reading_a_message.rb +32 -0
  9. data/examples/writing_a_message.rb +46 -0
  10. data/lib/protobuf/compiler/compiler.rb +9 -11
  11. data/lib/protobuf/compiler/nodes.rb +15 -7
  12. data/lib/protobuf/compiler/proto.y +56 -36
  13. data/lib/protobuf/compiler/proto_parser.rb +373 -236
  14. data/lib/protobuf/compiler/visitors.rb +5 -1
  15. data/lib/protobuf/descriptor/enum_descriptor.rb +1 -1
  16. data/lib/protobuf/message/decoder.rb +12 -19
  17. data/lib/protobuf/message/encoder.rb +5 -2
  18. data/lib/protobuf/message/enum.rb +1 -1
  19. data/lib/protobuf/message/field.rb +302 -298
  20. data/lib/protobuf/message/message.rb +63 -35
  21. data/lib/ruby_protobuf.rb +1 -1
  22. data/{bin → script}/mk_parser +0 -0
  23. data/test/merge.rb +1 -1
  24. data/test/proto/types.proto +20 -0
  25. data/test/test_addressbook.rb +1 -0
  26. data/test/test_compiler.rb +21 -7
  27. data/test/test_message.rb +19 -0
  28. data/test/test_optional_field.rb +80 -0
  29. data/test/test_repeated_types.rb +106 -0
  30. data/test/test_serialize.rb +34 -0
  31. data/test/test_standard_message.rb +10 -0
  32. data/test/test_types.rb +49 -4
  33. data/test/types.rb +23 -2
  34. metadata +22 -20
  35. data/lib/protobuf/compiler/compiler_old.rb +0 -123
  36. data/test/proto/addressbook.rb +0 -69
  37. data/test/proto/bool_default.pb.rb +0 -16
  38. data/test/proto/bool_default.proto +0 -3
  39. data/test/proto/float_default.proto +0 -2
@@ -29,7 +29,7 @@ module Protobuf
29
29
 
30
30
  class <<self
31
31
  include Protobuf::Protoable
32
- def fields; @fields ||= [] end #attr_reader :fields
32
+ def fields; @fields ||= {} end
33
33
 
34
34
  def extensions(range)
35
35
  @extension_fields = ExtensionFields.new range
@@ -53,7 +53,6 @@ module Protobuf
53
53
  Field number #{tag} has already been used in "#{self.name}" by field "#{fname}".
54
54
  eos
55
55
  field_hash[tag] = Protobuf::Field.build self, rule, type, fname, tag, opts
56
- #(@fields ||= {})[tag] = Protobuf::Field.build self, rule, type, fname, tag, opts
57
56
  end
58
57
 
59
58
  def extension_tag?(tag)
@@ -65,7 +64,8 @@ module Protobuf
65
64
  end
66
65
 
67
66
  def get_field_by_name(name)
68
- fields.values.find {|field| field.name == name.to_sym}
67
+ name = name.to_sym
68
+ fields.values.find {|field| field.name == name}
69
69
  end
70
70
 
71
71
  def get_field_by_tag(tag)
@@ -82,7 +82,8 @@ module Protobuf
82
82
 
83
83
  #TODO merge to get_field_by_name
84
84
  def get_ext_field_by_name(name)
85
- extension_fields.values.find {|field| field.name == name.to_sym}
85
+ name = name.to_sym
86
+ extension_fields.values.find {|field| field.name == name}
86
87
  end
87
88
 
88
89
  #TODO merge to get_field_by_tag
@@ -105,12 +106,16 @@ module Protobuf
105
106
  end
106
107
 
107
108
  def initialize(values={})
108
- fields.each do |tag, field|
109
+ @values = {}
110
+
111
+ self.class.fields.each do |tag, field|
109
112
  unless field.ready?
110
113
  field = field.setup
111
114
  self.class.class_eval {@fields[tag] = field}
112
115
  end
113
- field.define_accessor self
116
+ if field.repeated?
117
+ @values[field.name] = Protobuf::Field::FieldArray.new(field)
118
+ end
114
119
  end
115
120
 
116
121
  # TODO
@@ -119,25 +124,29 @@ module Protobuf
119
124
  field = field.setup
120
125
  self.class.class_eval {@extension_fields[tag] = field}
121
126
  end
122
- field.define_accessor self
127
+ if field.repeated?
128
+ @values[field.name] = Protobuf::Field::FieldArray.new(field)
129
+ end
123
130
  end
124
131
 
125
132
  values.each {|tag, val| self[tag] = val}
126
133
  end
127
134
 
128
135
  def initialized?
129
- fields.to_a.inject(true) do |result, (tag, field)|
130
- result and field.initialized?(self)
131
- end and
132
- extension_fields.to_a.inject(true) do |result, (tag, field)|
133
- result and field.initialized?(self)
134
- end
136
+ fields.all? {|tag, field| field.initialized?(self) } && \
137
+ extension_fields.all? {|tag, field| field.initialized?(self) }
138
+ end
139
+
140
+ def has_field?(tag_or_name)
141
+ field = get_field(tag_or_name) || get_ext_field(tag_or_name)
142
+ raise ArgumentError.new("unknown field: #{tag_or_name.inspect}") unless field
143
+ @values.has_key?(field.name)
135
144
  end
136
145
 
137
146
  def ==(obj)
138
147
  return false unless obj.is_a? self.class
139
148
  each_field do |field, value|
140
- return false unless value == obj[field.name]
149
+ return false unless value == obj.send(field.name)
141
150
  end
142
151
  true
143
152
  end
@@ -152,11 +161,12 @@ module Protobuf
152
161
  ret = self.class.new
153
162
  each_field do |field, value|
154
163
  if field.repeated?
164
+ field_array = ret.send(field.name)
155
165
  value.each do |v|
156
- ret[field.name] << (v.is_a?(Numeric) ? v : v.dup)
166
+ field_array << (v.is_a?(Numeric) ? v : v.dup)
157
167
  end
158
168
  else
159
- ret[field.name] = value.is_a?(Numeric) ? value : value.dup
169
+ ret.send("#{field.name}=", value.is_a?(Numeric) ? value : value.dup)
160
170
  end
161
171
  end
162
172
  ret
@@ -168,11 +178,31 @@ module Protobuf
168
178
  field_value_to_string = lambda do |field, value|
169
179
  ret +=
170
180
  if field.is_a? Protobuf::Field::MessageField
171
- "#{i}#{field.name} {\n#{value.inspect(indent + 1)}#{i}}\n"
181
+ if value.nil?
182
+ if $DEBUG
183
+ "#{i}#{field.name} {\n#{' ' * (indent + 1)}nil\n#{i}}\n"
184
+ else
185
+ "#{i}#{field.name} {}\n"
186
+ end
187
+ else
188
+ "#{i}#{field.name} {\n#{value.inspect(indent + 1)}#{i}}\n"
189
+ end
172
190
  elsif field.is_a? Protobuf::Field::EnumField
173
- "#{i}#{field.name}: #{field.type.name_by_value(value)}\n"
191
+ if field.optional? and not has_field?(field.name)
192
+ ''
193
+ else
194
+ "#{i}#{field.name}: #{field.type.name_by_value(value)}\n"
195
+ end
174
196
  else
175
- "#{i}#{field.name}: #{value.inspect}\n"
197
+ if $DEBUG
198
+ "#{i}#{field.name}: #{value.inspect}\n"
199
+ else
200
+ if field.optional? and not has_field?(field.name)
201
+ ''
202
+ else
203
+ "#{i}#{field.name}: #{value.inspect}\n"
204
+ end
205
+ end
176
206
  end
177
207
  end
178
208
  each_field do |field, value|
@@ -195,7 +225,7 @@ module Protobuf
195
225
  if filename.is_a? File
196
226
  parse_from filename
197
227
  else
198
- File.open(filename, 'r') do |f|
228
+ File.open(filename, 'rb') do |f|
199
229
  parse_from f
200
230
  end
201
231
  end
@@ -208,7 +238,9 @@ module Protobuf
208
238
  def serialize_to_string(string='')
209
239
  io = StringIO.new string
210
240
  serialize_to io
211
- io.string
241
+ result = io.string
242
+ result.force_encoding('ASCII-8BIT') if result.respond_to?(:force_encoding)
243
+ result
212
244
  end
213
245
  alias to_s serialize_to_string
214
246
 
@@ -216,7 +248,7 @@ module Protobuf
216
248
  if filename.is_a? File
217
249
  serialize_to filename
218
250
  else
219
- File.open(filename, 'w') do |f|
251
+ File.open(filename, 'wb') do |f|
220
252
  serialize_to f
221
253
  end
222
254
  end
@@ -233,8 +265,8 @@ module Protobuf
233
265
  end
234
266
 
235
267
  def set_field(tag, bytes)
236
- #get_field_by_tag(tag).set self, bytes # TODO
237
- (get_field_by_tag(tag) or get_ext_field_by_tag(tag)).set self, bytes
268
+ field = (get_field_by_tag(tag) or get_ext_field_by_tag(tag))
269
+ field.set self, bytes if field
238
270
  end
239
271
 
240
272
  def merge_field(tag, value)
@@ -243,22 +275,18 @@ module Protobuf
243
275
  end
244
276
 
245
277
  def [](tag_or_name)
246
- if field = get_field(tag_or_name)
247
- send field.name
248
- elsif field = get_ext_field(tag_or_name)
278
+ if field = get_field(tag_or_name) || get_ext_field(tag_or_name)
249
279
  send field.name
250
280
  else
251
- raise NoMethodError.new("No such method: #{tag_or_name.inspect}")
281
+ raise NoMethodError.new("No such field: #{tag_or_name.inspect}")
252
282
  end
253
283
  end
254
284
 
255
285
  def []=(tag_or_name, value)
256
- if field = get_field(tag_or_name) and not field.repeated?
257
- send "#{field.name}=", value
258
- elsif field = get_ext_field(tag_or_name) and not field.repeated?
286
+ if field = get_field(tag_or_name) || get_ext_field(tag_or_name)
259
287
  send "#{field.name}=", value
260
288
  else
261
- raise NoMethodError.new("No such method: #{tag_or_name.inspect}")
289
+ raise NoMethodError.new("No such field: #{tag_or_name.inspect}")
262
290
  end
263
291
  end
264
292
 
@@ -272,9 +300,9 @@ module Protobuf
272
300
  def get_ext_field_by_tag(tag); self.class.get_ext_field_by_tag(tag) end
273
301
  def get_ext_field(tag_or_name); self.class.get_ext_field(tag_or_name) end
274
302
 
275
- def each_field(&block)
276
- (fields.merge extension_fields).to_a.sort{|(t1, f1), (t2, f2)| t1 <=> t2}.each do |tag, field|
277
- block.call field, self[tag]
303
+ def each_field
304
+ (fields.merge extension_fields).sort_by {|tag, field| tag}.each do |tag, field|
305
+ yield field, send(field.name)
278
306
  end
279
307
  end
280
308
  end
@@ -1,3 +1,3 @@
1
1
  class RubyProtobuf
2
- VERSION = '0.3.2'
2
+ VERSION = '0.3.3'
3
3
  end
File without changes
@@ -37,4 +37,4 @@ module Test
37
37
  repeated :InnerMessage1, :repeate_message, 2
38
38
  required :InnerMessage2, :require_message, 3
39
39
  end
40
- end
40
+ end
@@ -14,4 +14,24 @@ message TestTypes {
14
14
  required bool type11 = 11;
15
15
  required string type12 = 12;
16
16
  required bytes type13 = 13;
17
+ required sfixed32 type14 = 14;
18
+ required sfixed64 type15 = 15;
19
+ }
20
+
21
+ message RepeatedTypes {
22
+ repeated double type1 = 1;
23
+ repeated float type2 = 2;
24
+ repeated int32 type3 = 3;
25
+ repeated int64 type4 = 4;
26
+ repeated uint32 type5 = 5;
27
+ repeated uint64 type6 = 6;
28
+ repeated sint32 type7 = 7;
29
+ repeated sint64 type8 = 8;
30
+ repeated fixed32 type9 = 9;
31
+ repeated fixed64 type10 = 10;
32
+ repeated bool type11 = 11;
33
+ repeated string type12 = 12;
34
+ repeated bytes type13 = 13;
35
+ repeated sfixed32 type14 = 14;
36
+ repeated sfixed64 type15 = 15;
17
37
  }
@@ -6,6 +6,7 @@ require 'test/addressbook'
6
6
  class AddressbookTest < Test::Unit::TestCase
7
7
  def test_enum
8
8
  phone_number = Tutorial::Person::PhoneNumber.new
9
+ assert_equal Tutorial::Person::PhoneType::HOME, phone_number.type
9
10
  phone_number.type = Tutorial::Person::PhoneType::MOBILE
10
11
  assert_equal 0, phone_number.type
11
12
  phone_number.type = Tutorial::Person::PhoneType::HOME
@@ -8,7 +8,15 @@ class CompilerTest < Test::Unit::TestCase
8
8
  assert_compile_proto <<-eos, 'test/proto/float_default.proto'
9
9
  ### Generated by rprotoc. DO NOT EDIT!
10
10
  ### <proto file: test/proto/float_default.proto>
11
- # message M { optional float f = 1 [default = 4.2]; }
11
+ # message M {
12
+ # optional float f = 1 [default = 4.2];
13
+ # optional float g = 2 [default = -4.2];
14
+ # optional float h = 3 [default = 4352];
15
+ # optional float i = 4 [default = 23145.2 ];
16
+ # optional float j = 5 [default = -5 ];
17
+ # optional float k = 6 [default = +23 ];
18
+ # optional float l = 7 [default = +23.42 ];
19
+ # }
12
20
  #
13
21
 
14
22
  require 'protobuf/message/message'
@@ -19,6 +27,12 @@ require 'protobuf/message/extend'
19
27
  class M < ::Protobuf::Message
20
28
  defined_in __FILE__
21
29
  optional :float, :f, 1, :default => 4.2
30
+ optional :float, :g, 2, :default => -4.2
31
+ optional :float, :h, 3, :default => 4352
32
+ optional :float, :i, 4, :default => 23145.2
33
+ optional :float, :j, 5, :default => -5
34
+ optional :float, :k, 6, :default => 23
35
+ optional :float, :l, 7, :default => 23.42
22
36
  end
23
37
  eos
24
38
  end
@@ -136,15 +150,15 @@ end
136
150
  def test_nested_message
137
151
  Protobuf::Visitor::CreateMessageVisitor.instance_eval {remove_const :Baaz}
138
152
  file_contents = Protobuf::Compiler.new.create_message('test/proto/nested.proto', '.', '.', false)
139
- assert_nothing_raised {eval file_contents}
153
+ assert_nothing_raised {Object.class_eval file_contents}
140
154
  assert_raise(TypeError) {Baaz.new.x = 1}
141
155
  assert_nothing_raised {Baaz.new.x = Foo::Bar.new}
142
156
  end
143
157
 
144
158
  def test_create_rpc
145
- file_contents = Protobuf::Compiler.new.create_rpc('test/proto/rpc.proto', '.', '.', false)
159
+ file_contents = Protobuf::Compiler.new.create_rpc('test/proto/rpc.proto', '.', 'test/proto', false)
146
160
 
147
- assert_source <<-eos, file_contents['./test/proto/address_book_service.rb']
161
+ assert_source <<-eos, file_contents['test/proto/address_book_service.rb']
148
162
  require 'protobuf/rpc/server'
149
163
  require 'protobuf/rpc/handler'
150
164
  require 'test/proto/rpc.pb'
@@ -177,14 +191,14 @@ class Tutorial::AddressBookService < Protobuf::Rpc::Server
177
191
  end
178
192
  eos
179
193
 
180
- assert_source <<-eos, file_contents['./test/proto/start_address_book_service']
194
+ assert_source <<-eos, file_contents['test/proto/start_address_book_service']
181
195
  #!/usr/bin/env ruby
182
196
  require 'address_book_service'
183
197
 
184
198
  Tutorial::AddressBookService.new(:port => 9999).start
185
199
  eos
186
200
 
187
- assert_source <<-eos, file_contents['./test/proto/client_search.rb']
201
+ assert_source <<-eos, file_contents['test/proto/client_search.rb']
188
202
  #!/usr/bin/env ruby
189
203
  require 'protobuf/rpc/client'
190
204
  require 'test/proto/rpc.pb'
@@ -204,7 +218,7 @@ Protobuf::Rpc::Client.new('localhost', 9999).call :search, request, response
204
218
  puts response
205
219
  eos
206
220
 
207
- assert_source <<-eos, file_contents['./test/proto/client_add.rb']
221
+ assert_source <<-eos, file_contents['test/proto/client_add.rb']
208
222
  #!/usr/bin/env ruby
209
223
  require 'protobuf/rpc/client'
210
224
  require 'test/proto/rpc.pb'
@@ -3,6 +3,9 @@ require 'test/addressbook'
3
3
  require 'test/merge'
4
4
  require 'test/unit'
5
5
 
6
+ # It should not conflict with Test::InnerMessage1 which is included in merge.proto
7
+ class InnerMessage1; end
8
+
6
9
  class MessageTest < Test::Unit::TestCase
7
10
  def test_equality
8
11
  person1 = Tutorial::Person.new :name => 'ando'
@@ -33,6 +36,22 @@ class MessageTest < Test::Unit::TestCase
33
36
  assert_equal 'Jiro', person.name
34
37
  assert_equal 300, person.id
35
38
  assert_equal 'jiro@ema.il', person.email
39
+
40
+ # initialize with array of hash
41
+ person = Tutorial::Person.new(:phone => [{:number => 'phone1'}, {:number => 'phone2'}])
42
+ assert_equal 'phone1', person.phone[0].number
43
+ assert_equal 'phone2', person.phone[1].number
44
+
45
+ # initalize with hash in hash
46
+ message = Test::MergeMessage.new(:require_message => { :name => 'name1', :repeate_message => [{:name => 'name2'}] })
47
+ assert_equal 'name1', message.require_message.name
48
+ assert_equal 'name2', message.require_message.repeate_message[0].name
49
+
50
+ message.require_message = { :name => 'name21' }
51
+ message.require_message.repeate_message = [ {:name => 'name22'} ]
52
+ assert_equal 'name21', message.require_message.name
53
+ assert_equal 'name22', message.require_message.repeate_message[0].name
54
+ assert_equal 1, message.require_message.repeate_message.size
36
55
  end
37
56
 
38
57
  def test_defined_filenames
@@ -0,0 +1,80 @@
1
+ require 'test/unit'
2
+ require 'test/optional_field'
3
+
4
+ class OptionalFieldTest < Test::Unit::TestCase
5
+ def test_accessor
6
+ message = Test::Optional_field::Message.new
7
+
8
+ # default values
9
+ assert !message.has_field?(:number)
10
+ assert_equal 20, message.number
11
+
12
+ assert !message.has_field?(:text)
13
+ assert_equal 'default string', message.text
14
+
15
+ assert !message.has_field?(:enum)
16
+ assert_equal 2, message.enum
17
+
18
+ assert !message.has_field?(:signed)
19
+ assert_equal(-100, message.signed)
20
+
21
+ # assign values
22
+ assert_nothing_raised { message.number = 100 }
23
+ assert message.has_field?(:number)
24
+ assert_equal 100, message.number
25
+
26
+ assert_nothing_raised { message.text = 'abc' }
27
+ assert message.has_field?(:text)
28
+ assert_equal 'abc', message.text
29
+
30
+ assert_nothing_raised { message.enum = Test::Optional_field::Message::Enum::A }
31
+ assert message.has_field?(:enum)
32
+ assert_equal 1, message.enum
33
+
34
+ assert_nothing_raised { message.signed = -20 }
35
+ assert message.has_field?(:signed)
36
+ assert_equal(-20, message.signed)
37
+ end
38
+
39
+ def test_serialize
40
+ message1 = Test::Optional_field::Message.new
41
+ message2 = Test::Optional_field::Message.new
42
+
43
+ # all fields are empty
44
+ serialized_string = message1.to_s
45
+ assert serialized_string.empty?
46
+ message2.parse_from_string(serialized_string)
47
+ assert_equal message1.number, message2.number
48
+ assert_equal message1.text, message2.text
49
+ assert_equal message1.enum, message2.enum
50
+ assert_equal message1.signed, message2.signed
51
+ assert !message2.has_field?(:number)
52
+ assert !message2.has_field?(:text)
53
+ assert !message2.has_field?(:enum)
54
+ assert !message2.has_field?(:signed)
55
+
56
+ # assign the value whith is equal to default value
57
+ message1 = Test::Optional_field::Message.new
58
+ message1.number = message1.number
59
+ message1.text = message1.text
60
+ message1.enum = message1.enum
61
+ message1.signed = message1.signed
62
+ serialized_string = message1.to_s
63
+ assert !serialized_string.empty?
64
+
65
+ # set some fields
66
+ message1 = Test::Optional_field::Message.new
67
+ message1.number = 100
68
+ message1.text = 'new text'
69
+ serialized_string = message1.to_s
70
+ message2.parse_from_string(serialized_string)
71
+ assert_equal message1.number, message2.number
72
+ assert_equal message1.text, message2.text
73
+ assert_equal message1.enum, message2.enum
74
+ assert_equal message1.signed, message2.signed
75
+ assert message2.has_field?(:number)
76
+ assert message2.has_field?(:text)
77
+ assert !message2.has_field?(:enum)
78
+ assert !message2.has_field?(:signed)
79
+ end
80
+ end