protobuf 1.0.0
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/.gitignore +5 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +28 -0
- data/README.md +216 -0
- data/Rakefile +1 -0
- data/bin/rpc_server +117 -0
- data/bin/rprotoc +46 -0
- data/examples/addressbook.pb.rb +55 -0
- data/examples/addressbook.proto +24 -0
- data/examples/reading_a_message.rb +32 -0
- data/examples/writing_a_message.rb +46 -0
- data/lib/protobuf.rb +6 -0
- data/lib/protobuf/common/exceptions.rb +11 -0
- data/lib/protobuf/common/logger.rb +64 -0
- data/lib/protobuf/common/util.rb +59 -0
- data/lib/protobuf/common/wire_type.rb +10 -0
- data/lib/protobuf/compiler/compiler.rb +52 -0
- data/lib/protobuf/compiler/nodes.rb +323 -0
- data/lib/protobuf/compiler/proto.y +216 -0
- data/lib/protobuf/compiler/proto2.ebnf +79 -0
- data/lib/protobuf/compiler/proto_parser.rb +1425 -0
- data/lib/protobuf/compiler/template/rpc_bin.erb +4 -0
- data/lib/protobuf/compiler/template/rpc_client.erb +18 -0
- data/lib/protobuf/compiler/template/rpc_service.erb +25 -0
- data/lib/protobuf/compiler/template/rpc_service_implementation.erb +42 -0
- data/lib/protobuf/compiler/visitors.rb +302 -0
- data/lib/protobuf/descriptor/descriptor.proto +286 -0
- data/lib/protobuf/descriptor/descriptor.rb +55 -0
- data/lib/protobuf/descriptor/descriptor_builder.rb +143 -0
- data/lib/protobuf/descriptor/descriptor_proto.rb +138 -0
- data/lib/protobuf/descriptor/enum_descriptor.rb +33 -0
- data/lib/protobuf/descriptor/field_descriptor.rb +49 -0
- data/lib/protobuf/descriptor/file_descriptor.rb +37 -0
- data/lib/protobuf/message/decoder.rb +83 -0
- data/lib/protobuf/message/encoder.rb +46 -0
- data/lib/protobuf/message/enum.rb +62 -0
- data/lib/protobuf/message/extend.rb +8 -0
- data/lib/protobuf/message/field.rb +701 -0
- data/lib/protobuf/message/message.rb +402 -0
- data/lib/protobuf/message/protoable.rb +38 -0
- data/lib/protobuf/rpc/buffer.rb +74 -0
- data/lib/protobuf/rpc/client.rb +268 -0
- data/lib/protobuf/rpc/client_connection.rb +225 -0
- data/lib/protobuf/rpc/error.rb +34 -0
- data/lib/protobuf/rpc/error/client_error.rb +31 -0
- data/lib/protobuf/rpc/error/server_error.rb +43 -0
- data/lib/protobuf/rpc/rpc.pb.rb +107 -0
- data/lib/protobuf/rpc/server.rb +183 -0
- data/lib/protobuf/rpc/service.rb +244 -0
- data/lib/protobuf/rpc/stat.rb +70 -0
- data/lib/protobuf/version.rb +3 -0
- data/proto/rpc.proto +73 -0
- data/protobuf.gemspec +25 -0
- data/script/mk_parser +2 -0
- data/spec/functional/embedded_service_spec.rb +7 -0
- data/spec/proto/test.pb.rb +31 -0
- data/spec/proto/test.proto +31 -0
- data/spec/proto/test_service.rb +30 -0
- data/spec/proto/test_service_impl.rb +17 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/unit/client_spec.rb +128 -0
- data/spec/unit/common/logger_spec.rb +121 -0
- data/spec/unit/enum_spec.rb +13 -0
- data/spec/unit/message_spec.rb +67 -0
- data/spec/unit/server_spec.rb +27 -0
- data/spec/unit/service_spec.rb +75 -0
- data/test/check_unbuild.rb +30 -0
- data/test/data/data.bin +3 -0
- data/test/data/data_source.py +14 -0
- data/test/data/types.bin +0 -0
- data/test/data/types_source.py +22 -0
- data/test/data/unk.png +0 -0
- data/test/proto/addressbook.pb.rb +66 -0
- data/test/proto/addressbook.proto +33 -0
- data/test/proto/addressbook_base.pb.rb +58 -0
- data/test/proto/addressbook_base.proto +26 -0
- data/test/proto/addressbook_ext.pb.rb +20 -0
- data/test/proto/addressbook_ext.proto +6 -0
- data/test/proto/collision.pb.rb +17 -0
- data/test/proto/collision.proto +5 -0
- data/test/proto/ext_collision.pb.rb +24 -0
- data/test/proto/ext_collision.proto +8 -0
- data/test/proto/ext_range.pb.rb +22 -0
- data/test/proto/ext_range.proto +7 -0
- data/test/proto/float_default.proto +10 -0
- data/test/proto/lowercase.pb.rb +30 -0
- data/test/proto/lowercase.proto +9 -0
- data/test/proto/merge.pb.rb +39 -0
- data/test/proto/merge.proto +15 -0
- data/test/proto/nested.pb.rb +30 -0
- data/test/proto/nested.proto +9 -0
- data/test/proto/optional_field.pb.rb +35 -0
- data/test/proto/optional_field.proto +12 -0
- data/test/proto/packed.pb.rb +22 -0
- data/test/proto/packed.proto +6 -0
- data/test/proto/rpc.proto +6 -0
- data/test/proto/types.pb.rb +84 -0
- data/test/proto/types.proto +37 -0
- data/test/test_addressbook.rb +56 -0
- data/test/test_compiler.rb +325 -0
- data/test/test_descriptor.rb +122 -0
- data/test/test_enum_value.rb +41 -0
- data/test/test_extension.rb +36 -0
- data/test/test_lowercase.rb +11 -0
- data/test/test_message.rb +128 -0
- data/test/test_optional_field.rb +103 -0
- data/test/test_packed_field.rb +40 -0
- data/test/test_parse.rb +15 -0
- data/test/test_repeated_types.rb +132 -0
- data/test/test_serialize.rb +61 -0
- data/test/test_standard_message.rb +96 -0
- data/test/test_types.rb +226 -0
- metadata +261 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
require 'pp'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
require 'protobuf/descriptor/descriptor'
|
|
4
|
+
require 'protobuf/message/decoder'
|
|
5
|
+
require 'protobuf/message/encoder'
|
|
6
|
+
require 'protobuf/message/field'
|
|
7
|
+
require 'protobuf/message/protoable'
|
|
8
|
+
require 'json'
|
|
9
|
+
|
|
10
|
+
module Protobuf
|
|
11
|
+
OPTIONS = {}
|
|
12
|
+
|
|
13
|
+
class Message
|
|
14
|
+
|
|
15
|
+
class ExtensionFields < Hash
|
|
16
|
+
def initialize(key_range=0..-1)
|
|
17
|
+
@key_range = key_range
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def []=(key, value)
|
|
21
|
+
raise RangeError, "#{key} is not in #{@key_range}" unless @key_range.include?(key)
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def include_tag?(tag)
|
|
26
|
+
@key_range.include?(tag)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class <<self
|
|
31
|
+
include Protoable
|
|
32
|
+
|
|
33
|
+
# Reserve field numbers for extensions. Don't use this method directly.
|
|
34
|
+
def extensions(range)
|
|
35
|
+
@extension_fields = ExtensionFields.new(range)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Define a required field. Don't use this method directly.
|
|
39
|
+
def required(type, name, tag, options={})
|
|
40
|
+
define_field(:required, type, name, tag, options)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Define a optional field. Don't use this method directly.
|
|
44
|
+
def optional(type, name, tag, options={})
|
|
45
|
+
define_field(:optional, type, name, tag, options)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Define a repeated field. Don't use this method directly.
|
|
49
|
+
def repeated(type, name, tag, options={})
|
|
50
|
+
define_field(:repeated, type, name, tag, options)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Define a field. Don't use this method directly.
|
|
54
|
+
def define_field(rule, type, fname, tag, options)
|
|
55
|
+
field_hash = options[:extension] ? extension_fields : fields
|
|
56
|
+
if field_hash.keys.include?(tag)
|
|
57
|
+
raise TagCollisionError, %!{Field number #{tag} has already been used in "#{self.name}" by field "#{fname}".!
|
|
58
|
+
end
|
|
59
|
+
field_hash[tag] = Field.build(self, rule, type, fname, tag, options)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def extension_tag?(tag)
|
|
63
|
+
extension_fields.include_tag?(tag)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# A collection of field object.
|
|
67
|
+
def fields
|
|
68
|
+
@fields ||= {}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# An extension field object.
|
|
72
|
+
def extension_fields
|
|
73
|
+
@extension_fields ||= ExtensionFields.new
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Find a field object by +name+.
|
|
77
|
+
def get_field_by_name(name)
|
|
78
|
+
name = name.to_sym
|
|
79
|
+
fields.values.find {|field| field.name == name}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Find a field object by +tag+ number.
|
|
83
|
+
def get_field_by_tag(tag)
|
|
84
|
+
fields[tag]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Find a field object by +tag_or_name+.
|
|
88
|
+
def get_field(tag_or_name)
|
|
89
|
+
case tag_or_name
|
|
90
|
+
when Integer then get_field_by_tag(tag_or_name)
|
|
91
|
+
when String, Symbol then get_field_by_name(tag_or_name)
|
|
92
|
+
else raise TypeError, tag_or_name.class
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
#TODO merge to get_field_by_name
|
|
97
|
+
def get_ext_field_by_name(name)
|
|
98
|
+
name = name.to_sym
|
|
99
|
+
extension_fields.values.find {|field| field.name == name}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
#TODO merge to get_field_by_tag
|
|
103
|
+
def get_ext_field_by_tag(tag)
|
|
104
|
+
extension_fields[tag]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
#TODO merge to get_field
|
|
108
|
+
def get_ext_field(tag_or_name)
|
|
109
|
+
case tag_or_name
|
|
110
|
+
when Integer then get_ext_field_by_tag(tag_or_name)
|
|
111
|
+
when String, Symbol then get_ext_field_by_name(tag_or_name)
|
|
112
|
+
else raise TypeError, tag_or_name.class
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def descriptor
|
|
117
|
+
@descriptor ||= Descriptor::Descriptor.new(self)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def initialize(values={})
|
|
122
|
+
@values = {}
|
|
123
|
+
|
|
124
|
+
self.class.fields.each do |tag, field|
|
|
125
|
+
unless field.ready?
|
|
126
|
+
field = field.setup
|
|
127
|
+
self.class.class_eval {@fields[tag] = field}
|
|
128
|
+
end
|
|
129
|
+
if field.repeated?
|
|
130
|
+
@values[field.name] = Field::FieldArray.new(field)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# TODO
|
|
135
|
+
self.class.extension_fields.each do |tag, field|
|
|
136
|
+
unless field.ready?
|
|
137
|
+
field = field.setup
|
|
138
|
+
self.class.class_eval {@extension_fields[tag] = field}
|
|
139
|
+
end
|
|
140
|
+
if field.repeated?
|
|
141
|
+
@values[field.name] = Field::FieldArray.new(field)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
values.each {|tag, val| self[tag] = val}
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def initialized?
|
|
149
|
+
fields.all? {|tag, field| field.initialized?(self) } && \
|
|
150
|
+
extension_fields.all? {|tag, field| field.initialized?(self) }
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def has_field?(tag_or_name)
|
|
154
|
+
field = get_field(tag_or_name) || get_ext_field(tag_or_name)
|
|
155
|
+
raise ArgumentError, "unknown field: #{tag_or_name.inspect}" unless field
|
|
156
|
+
@values.has_key?(field.name)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def ==(obj)
|
|
160
|
+
return false unless obj.is_a?(self.class)
|
|
161
|
+
each_field do |field, value|
|
|
162
|
+
return false unless value == obj.__send__(field.name)
|
|
163
|
+
end
|
|
164
|
+
true
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def clear!
|
|
168
|
+
@values.delete_if do |_, value|
|
|
169
|
+
if value.is_a?(Field::FieldArray)
|
|
170
|
+
value.clear
|
|
171
|
+
false
|
|
172
|
+
else
|
|
173
|
+
true
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
self
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def dup
|
|
180
|
+
copy_to(super, :dup)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def clone
|
|
184
|
+
copy_to(super, :clone)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def copy_to(object, method)
|
|
188
|
+
duplicate = proc {|obj|
|
|
189
|
+
case obj
|
|
190
|
+
when Message, String then obj.__send__(method)
|
|
191
|
+
else obj
|
|
192
|
+
end
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
object.__send__(:initialize)
|
|
196
|
+
@values.each do |name, value|
|
|
197
|
+
if value.is_a?(Field::FieldArray)
|
|
198
|
+
object.__send__(name).replace(value.map {|v| duplicate.call(v)})
|
|
199
|
+
else
|
|
200
|
+
object.__send__("#{name}=", duplicate.call(value))
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
object
|
|
204
|
+
end
|
|
205
|
+
private :copy_to
|
|
206
|
+
|
|
207
|
+
def inspect(indent=0)
|
|
208
|
+
result = []
|
|
209
|
+
i = ' ' * indent
|
|
210
|
+
field_value_to_string = lambda {|field, value|
|
|
211
|
+
result << \
|
|
212
|
+
if field.optional? && ! has_field?(field.name)
|
|
213
|
+
''
|
|
214
|
+
else
|
|
215
|
+
case field
|
|
216
|
+
when Field::MessageField
|
|
217
|
+
if value.nil?
|
|
218
|
+
"#{i}#{field.name} {}\n"
|
|
219
|
+
else
|
|
220
|
+
"#{i}#{field.name} {\n#{value.inspect(indent + 1)}#{i}}\n"
|
|
221
|
+
end
|
|
222
|
+
when Field::EnumField
|
|
223
|
+
if value.is_a?(EnumValue)
|
|
224
|
+
"#{i}#{field.name}: #{value.name}\n"
|
|
225
|
+
else
|
|
226
|
+
"#{i}#{field.name}: #{field.type.name_by_value(value)}\n"
|
|
227
|
+
end
|
|
228
|
+
else
|
|
229
|
+
"#{i}#{field.name}: #{value.inspect}\n"
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
}
|
|
233
|
+
each_field do |field, value|
|
|
234
|
+
if field.repeated?
|
|
235
|
+
value.each do |v|
|
|
236
|
+
field_value_to_string.call(field, v)
|
|
237
|
+
end
|
|
238
|
+
else
|
|
239
|
+
field_value_to_string.call(field, value)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
result.join
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def parse_from_string(string)
|
|
246
|
+
parse_from(StringIO.new(string))
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def parse_from_file(filename)
|
|
250
|
+
if filename.is_a?(File)
|
|
251
|
+
parse_from(filename)
|
|
252
|
+
else
|
|
253
|
+
File.open(filename, 'rb') do |f|
|
|
254
|
+
parse_from(f)
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def parse_from(stream)
|
|
260
|
+
Decoder.decode(stream, self)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def serialize_to_string(string='')
|
|
264
|
+
io = StringIO.new(string)
|
|
265
|
+
serialize_to(io)
|
|
266
|
+
result = io.string
|
|
267
|
+
result.force_encoding('ASCII-8BIT') if result.respond_to?(:force_encoding)
|
|
268
|
+
result
|
|
269
|
+
end
|
|
270
|
+
alias to_s serialize_to_string
|
|
271
|
+
|
|
272
|
+
def serialize_to_file(filename)
|
|
273
|
+
if filename.is_a?(File)
|
|
274
|
+
serialize_to(filename)
|
|
275
|
+
else
|
|
276
|
+
File.open(filename, 'wb') do |f|
|
|
277
|
+
serialize_to(f)
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def serialize_to(stream)
|
|
283
|
+
Encoder.encode(stream, self)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def merge_from(message)
|
|
287
|
+
# TODO
|
|
288
|
+
fields.each {|tag, field| merge_field(tag, message.__send__(field.name))}
|
|
289
|
+
extension_fields.each {|tag, field| merge_field(tag, message.__send__(field.name))}
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def set_field(tag, bytes)
|
|
293
|
+
field = (get_field_by_tag(tag) || get_ext_field_by_tag(tag))
|
|
294
|
+
field.set(self, bytes) if field
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def merge_field(tag, value)
|
|
298
|
+
#get_field_by_tag(tag).merge self, bytes #TODO
|
|
299
|
+
(get_field_by_tag(tag) || get_ext_field_by_tag(tag)).merge(self, value)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def [](tag_or_name)
|
|
303
|
+
if field = get_field(tag_or_name) || get_ext_field(tag_or_name)
|
|
304
|
+
__send__(field.name)
|
|
305
|
+
else
|
|
306
|
+
raise NoMethodError, "No such field: #{tag_or_name.inspect}"
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def []=(tag_or_name, value)
|
|
311
|
+
if field = get_field(tag_or_name) || get_ext_field(tag_or_name)
|
|
312
|
+
__send__("#{field.name}=", value)
|
|
313
|
+
else
|
|
314
|
+
raise NoMethodError, "No such field: #{tag_or_name.inspect}"
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# Returns a hash; which key is a tag number, and value is a field object.
|
|
319
|
+
def fields
|
|
320
|
+
self.class.fields
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# Returns field object or +nil+.
|
|
324
|
+
def get_field_by_name(name)
|
|
325
|
+
self.class.get_field_by_name(name)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Returns field object or +nil+.
|
|
329
|
+
def get_field_by_tag(tag)
|
|
330
|
+
self.class.get_field_by_tag(tag)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Returns field object or +nil+.
|
|
334
|
+
def get_field(tag_or_name)
|
|
335
|
+
self.class.get_field(tag_or_name)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# Returns extension fields. See Message#fields method.
|
|
339
|
+
def extension_fields
|
|
340
|
+
self.class.extension_fields
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def get_ext_field_by_name(name) # :nodoc:
|
|
344
|
+
self.class.get_ext_field_by_name(name)
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
def get_ext_field_by_tag(tag) # :nodoc:
|
|
348
|
+
self.class.get_ext_field_by_tag(tag)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def get_ext_field(tag_or_name) # :nodoc:
|
|
352
|
+
self.class.get_ext_field(tag_or_name)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# Iterate over a field collection.
|
|
356
|
+
# message.each_field do |field_object, value|
|
|
357
|
+
# # do something
|
|
358
|
+
# end
|
|
359
|
+
def each_field
|
|
360
|
+
fields.merge(extension_fields).sort_by {|tag, _| tag}.each do |_, field|
|
|
361
|
+
value = __send__(field.name)
|
|
362
|
+
yield(field, value)
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def to_hash
|
|
367
|
+
result = {}
|
|
368
|
+
build_value = lambda {|field, value|
|
|
369
|
+
if !field.optional? || (field.optional? && has_field?(field.name))
|
|
370
|
+
case field
|
|
371
|
+
when Field::MessageField
|
|
372
|
+
value.to_hash
|
|
373
|
+
when Field::EnumField
|
|
374
|
+
if value.is_a?(EnumValue)
|
|
375
|
+
value.to_i
|
|
376
|
+
elsif value.is_a?(Symbol)
|
|
377
|
+
field.type[value].to_i
|
|
378
|
+
else
|
|
379
|
+
value
|
|
380
|
+
end
|
|
381
|
+
else
|
|
382
|
+
value
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
}
|
|
386
|
+
each_field do |field, value|
|
|
387
|
+
if field.repeated?
|
|
388
|
+
result[field.name] = value.map do |v|
|
|
389
|
+
build_value.call(field, v)
|
|
390
|
+
end
|
|
391
|
+
else
|
|
392
|
+
result[field.name] = build_value.call(field, value)
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
result
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
def to_json
|
|
399
|
+
to_hash.to_json
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Protobuf
|
|
2
|
+
module Protoable
|
|
3
|
+
def defined_filenames
|
|
4
|
+
@defined_filenames ||= []
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def defined_in(filename)
|
|
8
|
+
path = File.expand_path(filename)
|
|
9
|
+
defined_filenames << path unless defined_filenames.include?(path)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def proto_filenames
|
|
13
|
+
defined_filenames.map do |filename|
|
|
14
|
+
retrieve_header(File.read(filename)).first
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def proto_contents
|
|
19
|
+
#TODO: temporary implementation because the result includes not only this message but also all messages
|
|
20
|
+
ret = {}
|
|
21
|
+
defined_filenames.each do |filename|
|
|
22
|
+
header = retrieve_header(File.read(filename))
|
|
23
|
+
ret[header.first] = header.last
|
|
24
|
+
end
|
|
25
|
+
ret
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def retrieve_header(contents)
|
|
29
|
+
if contents =~ /### Generated by rprotoc\. DO NOT EDIT!\n### <proto file: (.*)>\n((# .*\n)+)/
|
|
30
|
+
proto_filename = $1
|
|
31
|
+
proto_contents = $2.gsub(/^# /, '')
|
|
32
|
+
[proto_filename, proto_contents]
|
|
33
|
+
else
|
|
34
|
+
[nil, nil]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module Protobuf
|
|
2
|
+
module Rpc
|
|
3
|
+
class Buffer
|
|
4
|
+
|
|
5
|
+
attr_accessor :mode
|
|
6
|
+
attr_reader :data, :size
|
|
7
|
+
|
|
8
|
+
MODES = [:read, :write]
|
|
9
|
+
|
|
10
|
+
def initialize mode=:read, data=''
|
|
11
|
+
@data = data.is_a?(Protobuf::Message) ? data.serialize_to_string : data.to_s
|
|
12
|
+
@flush = false
|
|
13
|
+
self.mode = mode
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def mode= mode
|
|
17
|
+
if MODES.include? mode
|
|
18
|
+
@mode = mode
|
|
19
|
+
else
|
|
20
|
+
@mode = :read
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def write force_mode=true
|
|
25
|
+
if force_mode and reading?
|
|
26
|
+
mode = :write
|
|
27
|
+
elsif not force_mode and reading?
|
|
28
|
+
raise = 'You chose to write the buffer when in read mode'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
@size = @data.length
|
|
32
|
+
'%d-%s' % [@size, @data]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def << data
|
|
36
|
+
@data << data
|
|
37
|
+
if reading?
|
|
38
|
+
get_data_size
|
|
39
|
+
check_for_flush
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def reading?
|
|
44
|
+
mode == :read
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def writing?
|
|
48
|
+
mode == :write
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def flushed?
|
|
52
|
+
@flush
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def get_data_size
|
|
58
|
+
if @size.nil?
|
|
59
|
+
sliced_size = @data.slice! /^\d+-/
|
|
60
|
+
unless sliced_size.nil?
|
|
61
|
+
@size = sliced_size.gsub(/-/, '').to_i
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def check_for_flush
|
|
67
|
+
if not @size.nil? and @data.length == @size
|
|
68
|
+
@flush = true
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|