ruby-protocol-buffers 0.8.4
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.
- data/.document +3 -0
- data/.gitignore +11 -0
- data/LICENSE +22 -0
- data/README +82 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/bin/ruby-protoc +55 -0
- data/debian/changelog +105 -0
- data/debian/compatability +1 -0
- data/debian/control +12 -0
- data/debian/libprotobuf-ruby1.8.install +7 -0
- data/debian/protocol_buffers.rb +3 -0
- data/debian/rules +13 -0
- data/examples/json_protobuf.rb +90 -0
- data/ext/extconf.disabled.rb +3 -0
- data/ext/varint.c +65 -0
- data/lib/protocol_buffers.rb +5 -0
- data/lib/protocol_buffers/compiler.rb +48 -0
- data/lib/protocol_buffers/compiler/descriptor.pb.rb +236 -0
- data/lib/protocol_buffers/compiler/descriptor.proto +393 -0
- data/lib/protocol_buffers/compiler/file_descriptor_to_d.rb +195 -0
- data/lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb +173 -0
- data/lib/protocol_buffers/limited_io.rb +33 -0
- data/lib/protocol_buffers/runtime/decoder.rb +65 -0
- data/lib/protocol_buffers/runtime/encoder.rb +53 -0
- data/lib/protocol_buffers/runtime/enum.rb +4 -0
- data/lib/protocol_buffers/runtime/extend.rb +1 -0
- data/lib/protocol_buffers/runtime/field.rb +550 -0
- data/lib/protocol_buffers/runtime/message.rb +494 -0
- data/lib/protocol_buffers/runtime/service.rb +1 -0
- data/lib/protocol_buffers/runtime/varint.rb +62 -0
- data/spec/compiler_spec.rb +19 -0
- data/spec/fields_spec.rb +49 -0
- data/spec/proto_files/depends.proto +5 -0
- data/spec/proto_files/featureful.proto +54 -0
- data/spec/proto_files/no_package.proto +10 -0
- data/spec/proto_files/simple.proto +5 -0
- data/spec/runtime_spec.rb +430 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +8 -0
- metadata +128 -0
@@ -0,0 +1,494 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'protocol_buffers/runtime/field'
|
3
|
+
require 'protocol_buffers/runtime/encoder'
|
4
|
+
require 'protocol_buffers/runtime/decoder'
|
5
|
+
|
6
|
+
module ProtocolBuffers
|
7
|
+
|
8
|
+
# = Generated Code
|
9
|
+
#
|
10
|
+
# This text describes exactly what Ruby code the protocol buffer compiler
|
11
|
+
# generates for any given protocol definition. You should read the language
|
12
|
+
# guide before reading this document:
|
13
|
+
#
|
14
|
+
# http://code.google.com/apis/protocolbuffers/docs/proto.html
|
15
|
+
#
|
16
|
+
# == Packages
|
17
|
+
#
|
18
|
+
# If a package name is given in the <tt>.proto</tt> file, all top-level
|
19
|
+
# messages and enums in the file will be defined underneath a module with the
|
20
|
+
# same name as the package. The first letter of the package is capitalized if
|
21
|
+
# necessary. This applies to message and enum names as well, since Ruby
|
22
|
+
# classes and modules must be capitalized.
|
23
|
+
#
|
24
|
+
# For example, the following <tt>.proto</tt> file:
|
25
|
+
#
|
26
|
+
# package wootcakes;
|
27
|
+
# message uberWoot { }
|
28
|
+
#
|
29
|
+
# Will define a module +Wootcakes+ and a class <tt>Wootcakes::UberWoot</tt>
|
30
|
+
#
|
31
|
+
# == Messages
|
32
|
+
#
|
33
|
+
# Given a simple message definition:
|
34
|
+
#
|
35
|
+
# message Foo {}
|
36
|
+
#
|
37
|
+
# The compiler will generate a class called +Foo+, which subclasses
|
38
|
+
# ProtocolBuffers::Message.
|
39
|
+
#
|
40
|
+
# These generated classes are not designed for subclassing.
|
41
|
+
#
|
42
|
+
# Ruby message classes have no particular public methods or accessors other
|
43
|
+
# than those defined by ProtocolBuffers::Message and those generated for
|
44
|
+
# nested fields, messages, and enum types (see below).
|
45
|
+
#
|
46
|
+
# A message can be declared inside another message. For example:
|
47
|
+
# <tt>message Foo { message Bar { } }</tt>
|
48
|
+
#
|
49
|
+
# In this case, the +Bar+ class is declared inside the +Foo+ class, so you can
|
50
|
+
# access it as <tt>Foo::Bar</tt> (or if in package +Baz+,
|
51
|
+
# <tt>Baz::Foo::Bar</tt>)
|
52
|
+
#
|
53
|
+
# == Fields
|
54
|
+
#
|
55
|
+
# For each field in the message type, the corresponding class has a member
|
56
|
+
# with the same name as the field. How you can manipulate the member depends
|
57
|
+
# on its type.
|
58
|
+
#
|
59
|
+
# === Singular Fields
|
60
|
+
#
|
61
|
+
# If you have a singular (optional or repeated) field +foo+ of any non-message
|
62
|
+
# type, you can manipulate the field +foo+ as if it were a regular object
|
63
|
+
# attribute. For example, if +foo+'s type is <tt>int32</tt>, you can say:
|
64
|
+
#
|
65
|
+
# message.foo = 123
|
66
|
+
# puts message.foo
|
67
|
+
#
|
68
|
+
# Note that setting +foo+ to a value of the wrong type will raise a
|
69
|
+
# TypeError. Setting +foo+ to a value of the right type, but one that doesn't
|
70
|
+
# fit (such as assigning an out-of-bounds enum value) will raise an
|
71
|
+
# ArgumentError.
|
72
|
+
#
|
73
|
+
# If +foo+ is read when it is not set, its value is the default value for that
|
74
|
+
# field. To check if +foo+ is set, call <tt>has_foo?</tt> To clear +foo+, call
|
75
|
+
# <tt>message.foo = nil</tt>. For example:
|
76
|
+
#
|
77
|
+
# assert(!message.has_foo?)
|
78
|
+
# message.foo = 123
|
79
|
+
# assert(message.has_foo?)
|
80
|
+
# message.foo = nil
|
81
|
+
# assert(!message.has_foo?)
|
82
|
+
#
|
83
|
+
# === Singular String Fields
|
84
|
+
#
|
85
|
+
# String fields are treated like other singular fields, but note that the
|
86
|
+
# default value for string fields is frozen, so it is effectively an immutable
|
87
|
+
# string. Attempting to modify this default string will raise a TypeError,
|
88
|
+
# so assign a new string to the field instead.
|
89
|
+
#
|
90
|
+
# === Singular Message Fields
|
91
|
+
#
|
92
|
+
# Message types are a bit special, since they are mutable. Accessing an unset
|
93
|
+
# message field will return a default instance of the message type. Say you
|
94
|
+
# have the following <tt>.proto</tt> definition:
|
95
|
+
#
|
96
|
+
# message Foo {
|
97
|
+
# optional Bar bar = 1;
|
98
|
+
# }
|
99
|
+
# message Bar {
|
100
|
+
# optional int32 i = 1;
|
101
|
+
# }
|
102
|
+
#
|
103
|
+
# To set the message field, you can do either of the following:
|
104
|
+
#
|
105
|
+
# foo = Foo.new
|
106
|
+
# assert(!foo.has_bar?)
|
107
|
+
# foo.bar = Bar.new
|
108
|
+
# assert(foo.has_bar?)
|
109
|
+
#
|
110
|
+
# Or, to set bar, you can simply assign a value directly to a field within
|
111
|
+
# bar, and - presto! - foo has a bar field:
|
112
|
+
#
|
113
|
+
# foo = Foo.new
|
114
|
+
# assert(!foo.has_bar?)
|
115
|
+
# foo.bar.i = 1
|
116
|
+
# assert(foo.has_bar?)
|
117
|
+
#
|
118
|
+
# Note that simply reading a field inside bar does not set the field:
|
119
|
+
#
|
120
|
+
# foo = Foo.new
|
121
|
+
# assert(!foo.has_bar?)
|
122
|
+
# puts foo.bar.i
|
123
|
+
# assert(!foo.has_bar?)
|
124
|
+
#
|
125
|
+
# === Repeated Fields
|
126
|
+
#
|
127
|
+
# Repeated fields are represented as an object that acts like an Array.
|
128
|
+
# For example, given this message definition:
|
129
|
+
#
|
130
|
+
# message Foo {
|
131
|
+
# repeated int32 nums = 1;
|
132
|
+
# }
|
133
|
+
#
|
134
|
+
# You can do the following:
|
135
|
+
#
|
136
|
+
# foo = Foo.new
|
137
|
+
# foo.nums << 15
|
138
|
+
# foo.nums.push(32)
|
139
|
+
# assert(foo.nums.length == 2)
|
140
|
+
# assert(foo.nums[0] == 15)
|
141
|
+
# assert(foo.nums[1] == 32)
|
142
|
+
# foo.nums.each { |i| puts i }
|
143
|
+
# foo.nums[1] = 56
|
144
|
+
# assert(foo.nums[1] == 56)
|
145
|
+
#
|
146
|
+
# To clear a repeated field, call the <tt>clear</tt> method, or assign nil to
|
147
|
+
# it like a singular field.
|
148
|
+
#
|
149
|
+
# foo = Foo.new
|
150
|
+
# foo.nums << 15
|
151
|
+
# foo.nums.push(32)
|
152
|
+
# assert(foo.nums.length == 2)
|
153
|
+
# foo.nums.clear
|
154
|
+
# assert(foo.nums.length == 0)
|
155
|
+
# foo.nums = nil # equivalent to foo.nums.clear
|
156
|
+
# assert(foo.nums.length == 0)
|
157
|
+
#
|
158
|
+
# You can assign to a repeated field using an array, or any other object that
|
159
|
+
# responds to +each+. This will replace the current contents of the repeated
|
160
|
+
# field.
|
161
|
+
#
|
162
|
+
# foo = Foo.new
|
163
|
+
# foo.nums << 15
|
164
|
+
# foo.nums = [1, 3, 5]
|
165
|
+
# assert(foo.nums.length == 3)
|
166
|
+
# assert(foo.nums.to_a == [1,3,5])
|
167
|
+
#
|
168
|
+
# Repeated fields are always set, so <tt>foo.has_nums?</tt> will always be
|
169
|
+
# true. Repeated fields don't take up any space in a serialized message if
|
170
|
+
# they are empty.
|
171
|
+
#
|
172
|
+
# === Repeated Message Fields
|
173
|
+
#
|
174
|
+
# Repeated message fields work like other repeated fields. For example, given
|
175
|
+
# this message definition:
|
176
|
+
#
|
177
|
+
# message Foo {
|
178
|
+
# repeated Bar bars = 1;
|
179
|
+
# }
|
180
|
+
# message Bar {
|
181
|
+
# optional int32 i = 1;
|
182
|
+
# }
|
183
|
+
#
|
184
|
+
# You can do the following:
|
185
|
+
#
|
186
|
+
# foo = Foo.new
|
187
|
+
# foo.bars << Bar.new(:i => 15)
|
188
|
+
# foo.bars << Bar.new(:i => 32)
|
189
|
+
# assert(foo.bars.length == 2)
|
190
|
+
# assert(foo.bars[0].i == 15)
|
191
|
+
# assert(foo.bars[1].i == 32)
|
192
|
+
# foo.bars.each { |bar| puts bar.i }
|
193
|
+
# foo.bars[1].i = 56
|
194
|
+
# assert(foo.bars[1].i == 56)
|
195
|
+
#
|
196
|
+
# == Enumerations
|
197
|
+
#
|
198
|
+
# Enumerations are defined as a module with an integer constant for each
|
199
|
+
# valid value. For example, given:
|
200
|
+
#
|
201
|
+
# enum Foo {
|
202
|
+
# VALUE_A = 1;
|
203
|
+
# VALUE_B = 5;
|
204
|
+
# VALUE_C = 1234;
|
205
|
+
# }
|
206
|
+
#
|
207
|
+
# The following Ruby code will be generated:
|
208
|
+
#
|
209
|
+
# module Foo
|
210
|
+
# VALUE_A = 1
|
211
|
+
# VALUE_B = 5
|
212
|
+
# VALUE_C 1234
|
213
|
+
# end
|
214
|
+
#
|
215
|
+
# An exception will be thrown if an enum field is assigned a value not in the
|
216
|
+
# enum. Right now, this includes throwing an exception while parsing. This may
|
217
|
+
# change in the future to match the C++ behavior of treating it as an unknown
|
218
|
+
# tag number.
|
219
|
+
#
|
220
|
+
# == Extensions
|
221
|
+
#
|
222
|
+
# Protocol Buffer extensions are not currently supported in this library.
|
223
|
+
#
|
224
|
+
# == Services
|
225
|
+
#
|
226
|
+
# Protocol Buffer service (RPC) definitions are ignored.
|
227
|
+
|
228
|
+
class Message
|
229
|
+
# Create a new Message of this class.
|
230
|
+
#
|
231
|
+
# message = MyMessageClass.new(attributes)
|
232
|
+
# # is equivalent to
|
233
|
+
# message = MyMessageClass.new
|
234
|
+
# message.attributes = attributes
|
235
|
+
def initialize(attributes = {})
|
236
|
+
@set_fields = []
|
237
|
+
|
238
|
+
fields.each do |tag, field|
|
239
|
+
if field.repeated?
|
240
|
+
self.instance_variable_set("@#{field.name}", RepeatedField.new(field))
|
241
|
+
@set_fields[tag] = true # repeated fields are always "set"
|
242
|
+
else
|
243
|
+
value = field.default_value
|
244
|
+
self.__send__("#{field.name}=", value)
|
245
|
+
@set_fields[tag] = false
|
246
|
+
if field.class == Field::MessageField
|
247
|
+
value.notify_on_change(self, tag)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
self.attributes = attributes
|
253
|
+
end
|
254
|
+
|
255
|
+
# Serialize this Message to the given IO stream using the Protocol Buffer
|
256
|
+
# wire format.
|
257
|
+
#
|
258
|
+
# Equivalent to, but more efficient than
|
259
|
+
#
|
260
|
+
# io << message
|
261
|
+
#
|
262
|
+
# Returns +io+
|
263
|
+
def serialize(io)
|
264
|
+
Encoder.encode(io, self)
|
265
|
+
io
|
266
|
+
end
|
267
|
+
|
268
|
+
# Serialize this Message to a String and return it.
|
269
|
+
def serialize_to_string
|
270
|
+
sio = StringIO.new
|
271
|
+
serialize(sio)
|
272
|
+
return sio.string
|
273
|
+
end
|
274
|
+
alias_method :to_s, :serialize_to_string
|
275
|
+
|
276
|
+
# Parse a Message of this class from the given IO/String. Since Protocol
|
277
|
+
# Buffers are not length delimited, this will read until the end of the
|
278
|
+
# stream.
|
279
|
+
#
|
280
|
+
# This does not call clear! beforehand, so this is logically equivalent to
|
281
|
+
#
|
282
|
+
# new_message = self.class.new
|
283
|
+
# new_message.parse(io)
|
284
|
+
# merge_from(new_message)
|
285
|
+
def parse(io_or_string)
|
286
|
+
io = io_or_string
|
287
|
+
if io.is_a?(String)
|
288
|
+
io = StringIO.new(io)
|
289
|
+
end
|
290
|
+
Decoder.decode(io, self)
|
291
|
+
return self
|
292
|
+
end
|
293
|
+
|
294
|
+
# Shortcut, simply calls self.new.parse(io)
|
295
|
+
def self.parse(io)
|
296
|
+
self.new.parse(io)
|
297
|
+
end
|
298
|
+
|
299
|
+
# Merge the attribute values from +obj+ into this Message, which must be of
|
300
|
+
# the same class.
|
301
|
+
#
|
302
|
+
# Singular fields will be overwritten, except for embedded messages which
|
303
|
+
# will be merged. Repeated fields will be concatenated.
|
304
|
+
def merge_from(obj)
|
305
|
+
raise(ArgumentError, "Incompatible merge types: #{self.class} and #{obj.class}") unless obj.is_a?(self.class)
|
306
|
+
for tag, field in self.class.fields
|
307
|
+
next unless obj.value_for_tag?(tag)
|
308
|
+
value = obj.value_for_tag(tag)
|
309
|
+
merge_field(tag, value, field)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Parse the string into a new Message of this class, and merge it into the
|
314
|
+
# current message like +merge_from+.
|
315
|
+
def merge_from_string(string)
|
316
|
+
merge_from(self.class.new.parse(string))
|
317
|
+
end
|
318
|
+
|
319
|
+
# Assign values to attributes in bulk.
|
320
|
+
#
|
321
|
+
# message.attributes = { :field1 => value1, :field2 => value2 } -> message
|
322
|
+
def attributes=(hash = {})
|
323
|
+
hash.each do |name, value|
|
324
|
+
self.send("#{name}=", value)
|
325
|
+
end
|
326
|
+
self
|
327
|
+
end
|
328
|
+
|
329
|
+
# Comparison by class and field values.
|
330
|
+
def ==(obj)
|
331
|
+
return false unless obj.is_a?(self.class)
|
332
|
+
fields.each do |tag, field|
|
333
|
+
return false unless self.__send__(field.name) == obj.__send__(field.name)
|
334
|
+
end
|
335
|
+
return true
|
336
|
+
end
|
337
|
+
|
338
|
+
# Reset all fields to the default value.
|
339
|
+
def clear!
|
340
|
+
fields.each { |tag, field| self.__send__("#{field.name}=", nil) }
|
341
|
+
end
|
342
|
+
|
343
|
+
# This is a shallow copy.
|
344
|
+
def dup
|
345
|
+
ret = self.class.new
|
346
|
+
fields.each do |tag, field|
|
347
|
+
val = self.__send__(field.name)
|
348
|
+
ret.__send__("#{field.name}=", val)
|
349
|
+
end
|
350
|
+
return ret
|
351
|
+
end
|
352
|
+
|
353
|
+
# Returns a hash of { tag => ProtocolBuffers::Field }
|
354
|
+
def self.fields
|
355
|
+
@fields || @fields = {}
|
356
|
+
end
|
357
|
+
|
358
|
+
# Returns a hash of { tag => ProtocolBuffers::Field }
|
359
|
+
def fields
|
360
|
+
self.class.fields
|
361
|
+
end
|
362
|
+
|
363
|
+
# Find the field for the given attribute name. Returns a
|
364
|
+
# ProtocolBuffers::field
|
365
|
+
def self.field_for_name(name)
|
366
|
+
name = name.to_sym
|
367
|
+
field = fields.find { |tag,field| field.name == name }
|
368
|
+
field && field.last
|
369
|
+
end
|
370
|
+
|
371
|
+
# Equivalent to fields[tag]
|
372
|
+
def self.field_for_tag(tag)
|
373
|
+
fields[tag]
|
374
|
+
end
|
375
|
+
|
376
|
+
# Reflection: get the attribute value for the given tag id.
|
377
|
+
#
|
378
|
+
# message.value_for_tag(message.class.field_for_name(:f1).tag)
|
379
|
+
# # is equivalent to
|
380
|
+
# message.f1
|
381
|
+
def value_for_tag(tag)
|
382
|
+
self.__send__(fields[tag].name)
|
383
|
+
end
|
384
|
+
|
385
|
+
def set_value_for_tag(tag, value)
|
386
|
+
self.__send__("#{fields[tag].name}=", value)
|
387
|
+
end
|
388
|
+
|
389
|
+
# Reflection: does this Message have the field set?
|
390
|
+
#
|
391
|
+
# message.value_for_tag?(message.class.field_for_name(:f1).tag)
|
392
|
+
# # is equivalent to
|
393
|
+
# message.has_f1?
|
394
|
+
def value_for_tag?(tag)
|
395
|
+
@set_fields[tag] || false
|
396
|
+
end
|
397
|
+
|
398
|
+
def inspect
|
399
|
+
ret = StringIO.new
|
400
|
+
ret << "#<#{self.class.name}"
|
401
|
+
fields.each do |tag, field|
|
402
|
+
ret << " #{field.name}=#{field.inspect_value(self.__send__(field.name))}"
|
403
|
+
end
|
404
|
+
ret << ">"
|
405
|
+
return ret.string
|
406
|
+
end
|
407
|
+
|
408
|
+
def merge_field(tag, value, field = fields[tag]) # :nodoc:
|
409
|
+
if field.repeated?
|
410
|
+
if value.is_a?(Array)
|
411
|
+
self.__send__("#{field.name}=", self.__send__(field.name) + value)
|
412
|
+
else
|
413
|
+
self.__send__(field.name) << value
|
414
|
+
end
|
415
|
+
else
|
416
|
+
self.__send__("#{field.name}=", value)
|
417
|
+
@set_fields[tag] = true
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
def self.define_field(otype, type, name, tag, opts = {}) # :NODOC:
|
422
|
+
raise("gen_methods! already called, cannot add more fields") if @methods_generated
|
423
|
+
type = type.is_a?(Module) ? type : type.to_sym
|
424
|
+
name = name.to_sym
|
425
|
+
tag = tag.to_i
|
426
|
+
raise("Field already exists for tag: #{tag}") if fields[tag]
|
427
|
+
field = Field.create(self, otype, type, name, tag, opts)
|
428
|
+
fields[tag] = field
|
429
|
+
field.add_methods_to(self)
|
430
|
+
end
|
431
|
+
|
432
|
+
def self.required(type, name, tag, opts = {}) # :NODOC:
|
433
|
+
define_field(:required, type, name, tag, opts)
|
434
|
+
@has_required_field = true
|
435
|
+
end
|
436
|
+
|
437
|
+
def self.optional(type, name, tag, opts = {}) # :NODOC:
|
438
|
+
define_field(:optional, type, name, tag, opts)
|
439
|
+
end
|
440
|
+
|
441
|
+
def self.repeated(type, name, tag, opts = {}) # :NODOC:
|
442
|
+
define_field(:repeated, type, name, tag, opts)
|
443
|
+
end
|
444
|
+
|
445
|
+
def notify_on_change(parent, tag)
|
446
|
+
@parent_for_notify = parent
|
447
|
+
@tag_for_notify = tag
|
448
|
+
end
|
449
|
+
|
450
|
+
def default_changed(tag)
|
451
|
+
@set_fields[tag] = true
|
452
|
+
if @parent_for_notify
|
453
|
+
@parent_for_notify.default_changed(@tag_for_notify)
|
454
|
+
@parent_for_notify = @tag_for_notify = nil
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
def valid?
|
459
|
+
self.class.valid?(self)
|
460
|
+
end
|
461
|
+
|
462
|
+
def self.valid?(message)
|
463
|
+
return true unless @has_required_field
|
464
|
+
|
465
|
+
fields.each do |tag, field|
|
466
|
+
if field.otype == :required
|
467
|
+
return false unless message.value_for_tag?(tag)
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def remember_unknown_field(tag_int, value)
|
473
|
+
@unknown_fields || @unknown_fields = []
|
474
|
+
@unknown_fields << [tag_int, value]
|
475
|
+
end
|
476
|
+
|
477
|
+
# yields |tag_int, value| pairs
|
478
|
+
def each_unknown_field # :nodoc:
|
479
|
+
return unless @unknown_fields
|
480
|
+
@unknown_fields.each { |tag_int, value| yield tag_int, value }
|
481
|
+
end
|
482
|
+
|
483
|
+
# Generate the initialize method using reflection, to improve speed. This is
|
484
|
+
# called by the generated .pb.rb code, it's not necessary to call this
|
485
|
+
# method directly.
|
486
|
+
def self.gen_methods! # :NODOC:
|
487
|
+
@methods_generated = true
|
488
|
+
# these generated methods have gone away for now -- the infrastructure has
|
489
|
+
# been left in place, since they'll probably make their way back in at
|
490
|
+
# some point.
|
491
|
+
end
|
492
|
+
|
493
|
+
end
|
494
|
+
end
|