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
@@ -1,4 +1,4 @@
1
- #!/usr/bin/ruby
1
+ #!/usr/bin/env ruby
2
2
  require '<%= underscored_name %>'
3
3
 
4
4
  <%= module_name %>::<%= service_name %>.new(:port => <%= default_port %>).start
@@ -1,4 +1,4 @@
1
- #!/usr/bin/ruby
1
+ #!/usr/bin/env ruby
2
2
  require 'protobuf/rpc/client'
3
3
  require '<%= required_file %>'
4
4
 
@@ -1,14 +1,54 @@
1
1
  require 'erb'
2
+ require 'fileutils'
3
+ require 'protobuf/descriptor/descriptor_proto'
2
4
 
3
5
  module Protobuf
4
6
  module Visitor
5
- class CreateMessageVisitor
6
- attr_accessor :indent, :context
7
+ class Base
8
+ attr_reader :silent
7
9
 
8
- def initialize(proto_dir='.', out_dir='.')
10
+ def create_file_with_backup(filename, contents, executable=false)
11
+ if File.exist? filename
12
+ if File.read(filename) == contents
13
+ # do nothing
14
+ return
15
+ else
16
+ backup_filename = "#{filename}.#{Time.now.to_i}"
17
+ log_writing "#{backup_filename}", "backingup..."
18
+ FileUtils.copy filename, backup_filename
19
+ end
20
+ end
21
+
22
+ File.open(filename, 'w') do |file|
23
+ log_writing filename
24
+ FileUtils.mkpath File.dirname(filename)
25
+ file.write contents
26
+ end
27
+ FileUtils.chmod 0755, filename if executable
28
+ end
29
+
30
+ def log_writing(filename, message="writing...")
31
+ puts "#{filename} #{message}" unless silent
32
+ end
33
+ end
34
+
35
+ class CreateMessageVisitor < Base
36
+ attr_accessor :indent, :context, :attach_proto, :proto_file
37
+
38
+ def initialize(proto_file=nil, proto_dir='.', out_dir='.')
9
39
  @proto_dir, @out_dir = proto_dir, out_dir
10
40
  @indent = 0
11
41
  @context = []
42
+ @attach_proto = true
43
+ @proto_file = proto_file
44
+ end
45
+
46
+ def attach_proto?
47
+ @attach_proto
48
+ end
49
+
50
+ def commented_proto_contents
51
+ File.read(proto_file).gsub(/^/, '# ') if proto_file
12
52
  end
13
53
 
14
54
  def write(str)
@@ -47,20 +87,31 @@ module Protobuf
47
87
  end
48
88
 
49
89
  def visit(node)
50
- node.accept_message_creator self
90
+ node.accept_message_visitor self
51
91
  self
52
92
  end
53
93
 
54
94
  def required_message_from_proto(proto_file)
55
- rb_path = proto_file.sub(/\.proto$/, '.rb')
95
+ rb_path = proto_file.sub(/\.proto$/, '.pb.rb')
56
96
  unless File.exist?("#{@out_dir}/#{rb_path}")
57
97
  Compiler.compile proto_file, @proto_dir, @out_dir
58
98
  end
59
- rb_path.sub /\.rb$/, ''
99
+ rb_path.sub(/\.rb$/, '')
100
+ end
101
+
102
+ def create_files(filename, out_dir, file_create)
103
+ eval to_s # check the message
104
+ if file_create
105
+ log_writing filename
106
+ FileUtils.mkpath File.dirname(filename)
107
+ File.open(filename, 'w') {|file| file.write to_s}
108
+ else
109
+ to_s
110
+ end
60
111
  end
61
112
  end
62
113
 
63
- class CreateRpcVisitor
114
+ class CreateRpcVisitor < Base
64
115
  attr_accessor :package, :services, :current_service, :file_contents
65
116
 
66
117
  def initialize
@@ -70,7 +121,7 @@ module Protobuf
70
121
  end
71
122
 
72
123
  def visit(node)
73
- node.accept_rpc_creator self
124
+ node.accept_rpc_visitor self
74
125
  self
75
126
  end
76
127
 
@@ -78,8 +129,7 @@ module Protobuf
78
129
  (@services[@current_service] ||= []) << [name, request.first, response.first]
79
130
  end
80
131
 
81
- #def create_files(message_file, out_dir, create_file=true)
82
- def create_files(message_file, out_dir, create_file=false)
132
+ def create_files(message_file, out_dir, create_file=true)
83
133
  @create_file = create_file
84
134
  default_port = 9999
85
135
  @services.each do |service_name, rpcs|
@@ -91,7 +141,8 @@ module Protobuf
91
141
  create_service message_file, out_dir, underscored_name, message_module,
92
142
  service_name, default_port, rpcs, required_file
93
143
  rpcs.each do |name, request, response|
94
- create_client out_dir, underscored_name, default_port, name, request, response, message_module, required_file
144
+ create_client out_dir, underscored_name, default_port, name, request, response,
145
+ message_module, required_file
95
146
  end
96
147
  end
97
148
  @file_contents
@@ -100,21 +151,23 @@ module Protobuf
100
151
  def create_bin(out_dir, underscored_name, module_name, service_name, default_port)
101
152
  bin_filename = "#{out_dir}/start_#{underscored_name}"
102
153
  bin_contents = template_erb('rpc_bin').result binding
103
- File.open(bin_filename, 'w') {|f| f.write bin_contents} if @create_file
154
+ create_file_with_backup bin_filename, bin_contents, true if @create_file
104
155
  @file_contents[bin_filename] = bin_contents
105
156
  end
106
157
 
107
- def create_service(message_file, out_dir, underscored_name, module_name, service_name, default_port, rpcs, required_file)
158
+ def create_service(message_file, out_dir, underscored_name, module_name, service_name,
159
+ default_port, rpcs, required_file)
108
160
  service_filename = "#{out_dir}/#{underscored_name}.rb"
109
161
  service_contents = template_erb('rpc_service').result binding
110
- File.open(service_filename, 'w') {|f| f.write service_contents} if @create_file
162
+ create_file_with_backup service_filename, service_contents if @create_file
111
163
  @file_contents[service_filename] = service_contents
112
164
  end
113
165
 
114
- def create_client(out_dir, underscored_name, default_port, name, request, response, message_module, required_file)
166
+ def create_client(out_dir, underscored_name, default_port, name, request, response,
167
+ message_module, required_file)
115
168
  client_filename = "#{out_dir}/client_#{underscore name}.rb"
116
169
  client_contents = template_erb('rpc_client').result binding
117
- File.open(client_filename, 'w') {|f| f.write client_contents} if @create_file
170
+ create_file_with_backup client_filename, client_contents, true if @create_file
118
171
  @file_contents[client_filename] = client_contents
119
172
  end
120
173
 
@@ -128,5 +181,104 @@ module Protobuf
128
181
  ERB.new File.read("#{File.dirname(__FILE__)}/template/#{template}.erb"), nil, '-'
129
182
  end
130
183
  end
184
+
185
+ class CreateDescriptorVisitor < Base
186
+ attr_reader :file_descriptor
187
+ attr_accessor :filename
188
+
189
+ def initialize(filename=nil)
190
+ @context = []
191
+ @filename = filename
192
+ end
193
+
194
+ def visit(node)
195
+ node.accept_descriptor_visitor self
196
+ self
197
+ end
198
+
199
+ def in_context(descriptor, &block)
200
+ @context.push descriptor
201
+ block.call
202
+ @context.pop
203
+ end
204
+
205
+ def current_descriptor
206
+ @context.last
207
+ end
208
+
209
+ def file_descriptor=(descriptor)
210
+ @file_descriptor = descriptor
211
+ @file_descriptor.name = @filename
212
+ end
213
+
214
+ def add_option(name, value)
215
+ options =
216
+ case current_descriptor
217
+ when Google::Protobuf::FileDescriptorProto
218
+ Google::Protobuf::FileOptions.new
219
+ when Google::Protobuf::DescriptorProto
220
+ Google::Protobuf::MessageOptions.new
221
+ when Google::Protobuf::FieldDescriptorProto
222
+ Google::Protobuf::FieldOptions.new
223
+ when Google::Protobuf::EnumDescriptorProto
224
+ Google::Protobuf::EnumOptions.new
225
+ when Google::Protobuf::EnumValueDescriptorProto
226
+ Google::Protobuf::EnumValueOptions.new
227
+ when Google::Protobuf::ServiceDescriptorProto
228
+ Google::Protobuf::ServiceOptions.new
229
+ when Google::Protobuf::MethodDescriptorProto
230
+ Google::Protobuf::MethodOptions.new
231
+ else
232
+ raise ArgumentError.new('Invalid context')
233
+ end
234
+ #TODO how should options be handled?
235
+ #current_descriptor.options << option
236
+ end
237
+
238
+ def descriptor=(descriptor)
239
+ case current_descriptor
240
+ when Google::Protobuf::FileDescriptorProto
241
+ current_descriptor.message_type << descriptor
242
+ when Google::Protobuf::DescriptorProto
243
+ current_descriptor.nested_type << descriptor
244
+ else
245
+ raise ArgumentError.new('Invalid context')
246
+ end
247
+ end
248
+ alias message_descriptor= descriptor=
249
+
250
+ def enum_descriptor=(descriptor)
251
+ current_descriptor.enum_type << descriptor
252
+ end
253
+
254
+ def enum_value_descriptor=(descriptor)
255
+ current_descriptor.value << descriptor
256
+ end
257
+
258
+ def service_descriptor=(descriptor)
259
+ current_descriptor.service << descriptor
260
+ end
261
+
262
+ def method_descriptor=(descriptor)
263
+ current_descriptor.method << descriptor
264
+ end
265
+
266
+ def field_descriptor=(descriptor)
267
+ case current_descriptor
268
+ when Google::Protobuf::FileDescriptorProto
269
+ current_descriptor.extension << descriptor
270
+ when Google::Protobuf::DescriptorProto
271
+ current_descriptor.field << descriptor
272
+ #TODO: how should i distiguish between field and extension
273
+ #current_descriptor.extension << descriptor
274
+ else
275
+ raise ArgumentError.new('Invalid context')
276
+ end
277
+ end
278
+
279
+ def extension_range_descriptor=(descriptor)
280
+ current_descriptor.extension_range << descriptor
281
+ end
282
+ end
131
283
  end
132
284
  end
@@ -1,8 +1,11 @@
1
1
  require 'protobuf/descriptor/enum_descriptor'
2
+ require 'protobuf/message/protoable'
2
3
 
3
4
  module Protobuf
4
5
  class Enum
5
6
  class <<self
7
+ include Protobuf::Protoable
8
+
6
9
  def get_name_by_tag(tag)
7
10
  constants.find do |name|
8
11
  class_eval(name) == tag
@@ -128,20 +128,20 @@ module Protobuf
128
128
  raise NotImplementedError
129
129
  end
130
130
 
131
- def merge(message_instance, bytes)
131
+ def merge(message_instance, value)
132
132
  if repeated?
133
- merge_array method_instance, bytes
133
+ merge_array message_instance, value
134
134
  else
135
- merge_value method_instance, bytes
135
+ merge_value message_instance, value
136
136
  end
137
137
  end
138
138
 
139
- def merge_array(message_instance, bytes)
140
- raise NotImplementedError
139
+ def merge_array(message_instance, value)
140
+ message_instance[tag].concat value
141
141
  end
142
142
 
143
- def merge_value(message_instance, bytes)
144
- raise NotImplementedError
143
+ def merge_value(message_instance, value)
144
+ message_instance[tag] = value
145
145
  end
146
146
 
147
147
  def repeated?; rule == :repeated end
@@ -247,13 +247,13 @@ module Protobuf
247
247
  true
248
248
  end
249
249
 
250
- def set_bytes(method_instance, bytes)
251
- method_instance.send("#{name}=", bytes.pack('U*'))
250
+ def set_bytes(message_instance, bytes)
251
+ message_instance.send("#{name}=", bytes.pack('U*'))
252
252
  end
253
253
 
254
- def set_array(method_instance, bytes)
254
+ def set_array(message_instance, bytes)
255
255
  message = bytes.pack('U*')
256
- arr = method_instance.send name
256
+ arr = message_instance.send name
257
257
  arr << message
258
258
  end
259
259
 
@@ -267,20 +267,31 @@ module Protobuf
267
267
 
268
268
  class BytesField < BaseField
269
269
  def wire_type
270
- Protobuf::WireType::VARINT
270
+ Protobuf::WireType::LENGTH_DELIMITED
271
271
  end
272
272
 
273
273
  def typed_default_value(default=nil)
274
- default or []
274
+ default or ''
275
275
  end
276
276
 
277
- def set_bytes(method_instance, bytes)
278
- method_instance.send("#{name}=", bytes)
277
+ def acceptable?(val)
278
+ raise TypeError unless val.instance_of? String
279
+ true
280
+ end
281
+
282
+ def set_bytes(message_instance, bytes)
283
+ message_instance.send("#{name}=", bytes.pack('C*'))
284
+ end
285
+
286
+ def set_array(message_instance, bytes)
287
+ message = bytes.pack('C*')
288
+ arr = message_instance.send name
289
+ arr << message
279
290
  end
280
291
 
281
292
  def get_bytes(value)
282
- string_size = VarintField.get_bytes value.size
283
- string_size + value.pack('C*')
293
+ string_size = VarintField.get_bytes value.unpack('C*').size
294
+ string_size + value
284
295
  end
285
296
  end
286
297
 
@@ -293,13 +304,13 @@ module Protobuf
293
304
  default or 0
294
305
  end
295
306
 
296
- def set_bytes(method_instance, bytes)
307
+ def set_bytes(message_instance, bytes)
297
308
  # TODO should refactor using pack('w*')
298
309
  value = 0
299
310
  bytes.each_with_index do |byte, index|
300
311
  value |= byte << (7 * index)
301
312
  end
302
- method_instance.send("#{name}=", value)
313
+ message_instance.send("#{name}=", value)
303
314
  end
304
315
 
305
316
  def self.get_bytes(value)
@@ -357,7 +368,7 @@ module Protobuf
357
368
  def self.max; 1.0/0.0 end
358
369
  def self.min; -1.0/0.0 end
359
370
 
360
- def set_bytes(method_instance, bytes)
371
+ def set_bytes(message_instance, bytes)
361
372
  # TODO use only bit-operations
362
373
  byte = bytes.first
363
374
  value =
@@ -366,7 +377,7 @@ module Protobuf
366
377
  else
367
378
  -(byte + 1) / 2
368
379
  end
369
- method_instance.send("#{name}=", value)
380
+ message_instance.send("#{name}=", value)
370
381
  end
371
382
 
372
383
  def get_bytes(value)
@@ -379,7 +390,7 @@ module Protobuf
379
390
  def self.max; 1.0/0.0 end
380
391
  def self.min; -1.0/0.0 end
381
392
 
382
- def set_bytes(method_instance, bytes)
393
+ def set_bytes(message_instance, bytes)
383
394
  # TODO use only bit-operations
384
395
  byte = bytes.first
385
396
  value =
@@ -388,7 +399,7 @@ module Protobuf
388
399
  else
389
400
  -(byte + 1) / 2
390
401
  end
391
- method_instance.send("#{name}=", value)
402
+ message_instance.send("#{name}=", value)
392
403
  end
393
404
 
394
405
  def get_bytes(value)
@@ -412,8 +423,8 @@ module Protobuf
412
423
  -(2**(64/2) - 1)
413
424
  end
414
425
 
415
- def set_bytes(method_instance, bytes)
416
- method_instance.send("#{name}=", bytes.unpack('E').first)
426
+ def set_bytes(message_instance, bytes)
427
+ message_instance.send("#{name}=", bytes.unpack('E').first)
417
428
  end
418
429
 
419
430
  def get_bytes(value)
@@ -442,8 +453,8 @@ module Protobuf
442
453
  -(2**(32/2) - 1)
443
454
  end
444
455
 
445
- def set_bytes(method_instance, bytes)
446
- method_instance.send("#{name}=", bytes.unpack('e').first)
456
+ def set_bytes(message_instance, bytes)
457
+ message_instance.send("#{name}=", bytes.unpack('e').first)
447
458
  end
448
459
 
449
460
  def get_bytes(value)
@@ -470,8 +481,8 @@ module Protobuf
470
481
  0
471
482
  end
472
483
 
473
- def set_bytes(method_instance, bytes)
474
- method_instance.send("#{name}=", bytes.unpack('L').first)
484
+ def set_bytes(message_instance, bytes)
485
+ message_instance.send("#{name}=", bytes.unpack('L').first)
475
486
  end
476
487
 
477
488
  def get_bytes(value)
@@ -492,8 +503,8 @@ module Protobuf
492
503
  0
493
504
  end
494
505
 
495
- def set_bytes(method_instance, bytes)
496
- method_instance.send("#{name}=", bytes.unpack('l').first)
506
+ def set_bytes(message_instance, bytes)
507
+ message_instance.send("#{name}=", bytes.unpack('l').first)
497
508
  end
498
509
 
499
510
  def get_bytes(value)
@@ -539,8 +550,8 @@ module Protobuf
539
550
  true
540
551
  end
541
552
 
542
- def set_bytes(method_instance, bytes)
543
- method_instance.send("#{name}=", bytes.first == 1)
553
+ def set_bytes(message_instance, bytes)
554
+ message_instance.send("#{name}=", bytes.first == 1)
544
555
  end
545
556
 
546
557
  def get_bytes(value)
@@ -566,18 +577,18 @@ module Protobuf
566
577
  true
567
578
  end
568
579
 
569
- def set_bytes(method_instance, bytes)
580
+ def set_bytes(message_instance, bytes)
570
581
  message = type.new
571
582
  #message.parse_from bytes
572
583
  message.parse_from_string bytes.pack('U*') # TODO
573
- method_instance.send("#{name}=", message)
584
+ message_instance.send("#{name}=", message)
574
585
  end
575
586
 
576
- def set_array(method_instance, bytes)
587
+ def set_array(message_instance, bytes)
577
588
  message = type.new
578
589
  #message.parse_from bytes
579
590
  message.parse_from_string bytes.pack('U*')
580
- arr = method_instance.send name
591
+ arr = message_instance.send name
581
592
  arr << message
582
593
  end
583
594
 
@@ -590,6 +601,10 @@ module Protobuf
590
601
  #bytes + string_size
591
602
  string_size + bytes.pack('C*')
592
603
  end
604
+
605
+ def merge_value(message_instance, value)
606
+ message_instance[tag].merge_from value
607
+ end
593
608
  end
594
609
 
595
610
  class EnumField < VarintField