ruby_protobuf 0.3.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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