macks-ruby_protobuf 0.3.2.1
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/History.txt +14 -0
- data/Manifest.txt +74 -0
- data/README.txt +58 -0
- data/Rakefile +18 -0
- data/bin/mk_parser +2 -0
- data/bin/rprotoc +36 -0
- data/examples/addressbook.pb.rb +56 -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/common/wire_type.rb +10 -0
- data/lib/protobuf/compiler/compiler.rb +54 -0
- data/lib/protobuf/compiler/nodes.rb +319 -0
- data/lib/protobuf/compiler/proto.y +203 -0
- data/lib/protobuf/compiler/proto2.ebnf +79 -0
- data/lib/protobuf/compiler/proto_parser.rb +1394 -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/visitors.rb +288 -0
- data/lib/protobuf/descriptor/descriptor.proto +286 -0
- data/lib/protobuf/descriptor/descriptor.rb +54 -0
- data/lib/protobuf/descriptor/descriptor_builder.rb +144 -0
- data/lib/protobuf/descriptor/descriptor_proto.rb +119 -0
- data/lib/protobuf/descriptor/enum_descriptor.rb +33 -0
- data/lib/protobuf/descriptor/field_descriptor.rb +50 -0
- data/lib/protobuf/descriptor/file_descriptor.rb +38 -0
- data/lib/protobuf/message/decoder.rb +93 -0
- data/lib/protobuf/message/encoder.rb +37 -0
- data/lib/protobuf/message/enum.rb +28 -0
- data/lib/protobuf/message/extend.rb +8 -0
- data/lib/protobuf/message/field.rb +654 -0
- data/lib/protobuf/message/message.rb +308 -0
- data/lib/protobuf/message/protoable.rb +37 -0
- data/lib/protobuf/message/service.rb +9 -0
- data/lib/protobuf/rpc/client.rb +19 -0
- data/lib/protobuf/rpc/handler.rb +17 -0
- data/lib/protobuf/rpc/server.rb +39 -0
- data/lib/ruby_protobuf.rb +3 -0
- data/test/addressbook.rb +98 -0
- data/test/addressbook_base.rb +62 -0
- data/test/addressbook_ext.rb +12 -0
- data/test/check_unbuild.rb +30 -0
- data/test/collision.rb +18 -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/ext_collision.rb +25 -0
- data/test/ext_range.rb +23 -0
- data/test/merge.rb +40 -0
- data/test/nested.rb +25 -0
- data/test/proto/addressbook.proto +31 -0
- data/test/proto/addressbook_base.proto +26 -0
- data/test/proto/addressbook_ext.proto +6 -0
- data/test/proto/collision.proto +5 -0
- data/test/proto/ext_collision.proto +8 -0
- data/test/proto/ext_range.proto +7 -0
- data/test/proto/merge.proto +15 -0
- data/test/proto/nested.proto +7 -0
- data/test/proto/rpc.proto +6 -0
- data/test/proto/types.proto +17 -0
- data/test/test_addressbook.rb +43 -0
- data/test/test_compiler.rb +313 -0
- data/test/test_descriptor.rb +122 -0
- data/test/test_extension.rb +40 -0
- data/test/test_message.rb +106 -0
- data/test/test_optional_field.rb +68 -0
- data/test/test_parse.rb +15 -0
- data/test/test_ruby_protobuf.rb +1 -0
- data/test/test_serialize.rb +42 -0
- data/test/test_standard_message.rb +96 -0
- data/test/test_types.rb +181 -0
- data/test/types.rb +22 -0
- metadata +150 -0
@@ -0,0 +1,308 @@
|
|
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
|
+
|
9
|
+
module Protobuf
|
10
|
+
OPTIONS = {}
|
11
|
+
|
12
|
+
class Message
|
13
|
+
class TagCollisionError < StandardError; end
|
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.new("#{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 Protobuf::Protoable
|
32
|
+
def fields; @fields ||= {} end
|
33
|
+
|
34
|
+
def extensions(range)
|
35
|
+
@extension_fields = ExtensionFields.new range
|
36
|
+
end
|
37
|
+
|
38
|
+
def required(type, name, tag, opts={})
|
39
|
+
define_field :required, type, name, tag, opts
|
40
|
+
end
|
41
|
+
|
42
|
+
def optional(type, name, tag, opts={})
|
43
|
+
define_field :optional, type, name, tag, opts
|
44
|
+
end
|
45
|
+
|
46
|
+
def repeated(type, name, tag, opts={})
|
47
|
+
define_field :repeated, type, name, tag, opts
|
48
|
+
end
|
49
|
+
|
50
|
+
def define_field(rule, type, fname, tag, opts={})
|
51
|
+
field_hash = opts[:extension] ? extension_fields : (@fields ||= {})
|
52
|
+
raise Protobuf::Message::TagCollisionError.new(<<-eos.strip) if field_hash.keys.include? tag
|
53
|
+
Field number #{tag} has already been used in "#{self.name}" by field "#{fname}".
|
54
|
+
eos
|
55
|
+
field_hash[tag] = Protobuf::Field.build self, rule, type, fname, tag, opts
|
56
|
+
end
|
57
|
+
|
58
|
+
def extension_tag?(tag)
|
59
|
+
extension_fields.include_tag? tag
|
60
|
+
end
|
61
|
+
|
62
|
+
def extension_fields
|
63
|
+
@extension_fields ||= ExtensionFields.new
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_field_by_name(name)
|
67
|
+
fields.values.find {|field| field.name == name.to_sym}
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_field_by_tag(tag)
|
71
|
+
fields[tag]
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_field(tag_or_name)
|
75
|
+
case tag_or_name
|
76
|
+
when Integer; get_field_by_tag tag_or_name
|
77
|
+
when String, Symbol; get_field_by_name tag_or_name
|
78
|
+
else; raise TypeError.new(tag_or_name.class)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
#TODO merge to get_field_by_name
|
83
|
+
def get_ext_field_by_name(name)
|
84
|
+
extension_fields.values.find {|field| field.name == name.to_sym}
|
85
|
+
end
|
86
|
+
|
87
|
+
#TODO merge to get_field_by_tag
|
88
|
+
def get_ext_field_by_tag(tag)
|
89
|
+
extension_fields[tag]
|
90
|
+
end
|
91
|
+
|
92
|
+
#TODO merge to get_field
|
93
|
+
def get_ext_field(tag_or_name)
|
94
|
+
case tag_or_name
|
95
|
+
when Integer; get_ext_field_by_tag tag_or_name
|
96
|
+
when String, Symbol; get_ext_field_by_name tag_or_name
|
97
|
+
else; raise TypeError.new(tag_or_name.class)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def descriptor
|
102
|
+
@descriptor ||= Protobuf::Descriptor::Descriptor.new(self)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def initialize(values={})
|
107
|
+
@values = {}
|
108
|
+
|
109
|
+
fields.each do |tag, field|
|
110
|
+
unless field.ready?
|
111
|
+
field = field.setup
|
112
|
+
self.class.class_eval {@fields[tag] = field}
|
113
|
+
end
|
114
|
+
field.define_accessor self
|
115
|
+
end
|
116
|
+
|
117
|
+
# TODO
|
118
|
+
self.class.extension_fields.each do |tag, field|
|
119
|
+
unless field.ready?
|
120
|
+
field = field.setup
|
121
|
+
self.class.class_eval {@extension_fields[tag] = field}
|
122
|
+
end
|
123
|
+
field.define_accessor self
|
124
|
+
end
|
125
|
+
|
126
|
+
values.each {|tag, val| self[tag] = val}
|
127
|
+
end
|
128
|
+
|
129
|
+
def initialized?
|
130
|
+
fields.to_a.inject(true) do |result, (tag, field)|
|
131
|
+
result and field.initialized?(self)
|
132
|
+
end and
|
133
|
+
extension_fields.to_a.inject(true) do |result, (tag, field)|
|
134
|
+
result and field.initialized?(self)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def has_field?(tag_or_name)
|
139
|
+
field = get_field(tag_or_name) || get_ext_field(tag_or_name)
|
140
|
+
raise ArgumentError.new("unknown field: #{tag_or_name.inspect}") unless field
|
141
|
+
@values.has_key?(field.name)
|
142
|
+
end
|
143
|
+
|
144
|
+
def ==(obj)
|
145
|
+
return false unless obj.is_a? self.class
|
146
|
+
each_field do |field, value|
|
147
|
+
return false unless value == obj[field.name]
|
148
|
+
end
|
149
|
+
true
|
150
|
+
end
|
151
|
+
|
152
|
+
def clear!
|
153
|
+
each_field do |field, value|
|
154
|
+
field.clear self
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def dup
|
159
|
+
ret = self.class.new
|
160
|
+
each_field do |field, value|
|
161
|
+
if field.repeated?
|
162
|
+
value.each do |v|
|
163
|
+
ret[field.name] << (v.is_a?(Numeric) ? v : v.dup)
|
164
|
+
end
|
165
|
+
else
|
166
|
+
ret[field.name] = value.is_a?(Numeric) ? value : value.dup
|
167
|
+
end
|
168
|
+
end
|
169
|
+
ret
|
170
|
+
end
|
171
|
+
|
172
|
+
def inspect(indent=0)
|
173
|
+
ret = ''
|
174
|
+
i = ' ' * indent
|
175
|
+
field_value_to_string = lambda do |field, value|
|
176
|
+
ret +=
|
177
|
+
if field.is_a? Protobuf::Field::MessageField
|
178
|
+
if value.nil?
|
179
|
+
if $DEBUG
|
180
|
+
"#{i}#{field.name} {\n#{' ' * (indent + 1)}nil\n#{i}}\n"
|
181
|
+
else
|
182
|
+
"#{i}#{field.name} {}\n"
|
183
|
+
end
|
184
|
+
else
|
185
|
+
"#{i}#{field.name} {\n#{value.inspect(indent + 1)}#{i}}\n"
|
186
|
+
end
|
187
|
+
elsif field.is_a? Protobuf::Field::EnumField
|
188
|
+
if field.optional? and not has_field?(field.name)
|
189
|
+
''
|
190
|
+
else
|
191
|
+
"#{i}#{field.name}: #{field.type.name_by_value(value)}\n"
|
192
|
+
end
|
193
|
+
else
|
194
|
+
if $DEBUG
|
195
|
+
"#{i}#{field.name}: #{value.inspect}\n"
|
196
|
+
else
|
197
|
+
if field.optional? and not has_field?(field.name)
|
198
|
+
''
|
199
|
+
else
|
200
|
+
"#{i}#{field.name}: #{value.inspect}\n"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
each_field do |field, value|
|
206
|
+
if field.repeated?
|
207
|
+
value.each do |v|
|
208
|
+
field_value_to_string.call field, v
|
209
|
+
end
|
210
|
+
else
|
211
|
+
field_value_to_string.call field, value
|
212
|
+
end
|
213
|
+
end
|
214
|
+
ret
|
215
|
+
end
|
216
|
+
|
217
|
+
def parse_from_string(string)
|
218
|
+
parse_from StringIO.new(string)
|
219
|
+
end
|
220
|
+
|
221
|
+
def parse_from_file(filename)
|
222
|
+
if filename.is_a? File
|
223
|
+
parse_from filename
|
224
|
+
else
|
225
|
+
File.open(filename, 'r') do |f|
|
226
|
+
parse_from f
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def parse_from(stream)
|
232
|
+
Protobuf::Decoder.decode stream, self
|
233
|
+
end
|
234
|
+
|
235
|
+
def serialize_to_string(string='')
|
236
|
+
io = StringIO.new string
|
237
|
+
serialize_to io
|
238
|
+
io.string
|
239
|
+
end
|
240
|
+
alias to_s serialize_to_string
|
241
|
+
|
242
|
+
def serialize_to_file(filename)
|
243
|
+
if filename.is_a? File
|
244
|
+
serialize_to filename
|
245
|
+
else
|
246
|
+
File.open(filename, 'w') do |f|
|
247
|
+
serialize_to f
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def serialize_to(stream)
|
253
|
+
Protobuf::Encoder.encode stream, self
|
254
|
+
end
|
255
|
+
|
256
|
+
def merge_from(message)
|
257
|
+
# TODO
|
258
|
+
fields.each {|tag, field| merge_field tag, message[tag]}
|
259
|
+
self.class.extension_fields.each {|tag, field| merge_field tag, message[tag]}
|
260
|
+
end
|
261
|
+
|
262
|
+
def set_field(tag, bytes)
|
263
|
+
#get_field_by_tag(tag).set self, bytes # TODO
|
264
|
+
(get_field_by_tag(tag) or get_ext_field_by_tag(tag)).set self, bytes
|
265
|
+
end
|
266
|
+
|
267
|
+
def merge_field(tag, value)
|
268
|
+
#get_field_by_tag(tag).merge self, bytes #TODO
|
269
|
+
(get_field_by_tag(tag) or get_ext_field_by_tag(tag)).merge self, value
|
270
|
+
end
|
271
|
+
|
272
|
+
def [](tag_or_name)
|
273
|
+
if field = get_field(tag_or_name)
|
274
|
+
send field.name
|
275
|
+
elsif field = get_ext_field(tag_or_name)
|
276
|
+
send field.name
|
277
|
+
else
|
278
|
+
raise NoMethodError.new("No such method: #{tag_or_name.inspect}")
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def []=(tag_or_name, value)
|
283
|
+
if field = get_field(tag_or_name) and not field.repeated?
|
284
|
+
send "#{field.name}=", value
|
285
|
+
elsif field = get_ext_field(tag_or_name) and not field.repeated?
|
286
|
+
send "#{field.name}=", value
|
287
|
+
else
|
288
|
+
raise NoMethodError.new("No such method: #{tag_or_name.inspect}")
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def fields; self.class.fields end
|
293
|
+
def get_field_by_name(name); self.class.get_field_by_name(name) end
|
294
|
+
def get_field_by_tag(tag); self.class.get_field_by_tag(tag) end
|
295
|
+
def get_field(tag_or_name); self.class.get_field(tag_or_name) end
|
296
|
+
|
297
|
+
def extension_fields; self.class.extension_fields end
|
298
|
+
def get_ext_field_by_name(name); self.class.get_ext_field_by_name(name) end
|
299
|
+
def get_ext_field_by_tag(tag); self.class.get_ext_field_by_tag(tag) end
|
300
|
+
def get_ext_field(tag_or_name); self.class.get_ext_field(tag_or_name) end
|
301
|
+
|
302
|
+
def each_field(&block)
|
303
|
+
(fields.merge extension_fields).to_a.sort{|(t1, f1), (t2, f2)| t1 <=> t2}.each do |tag, field|
|
304
|
+
block.call field, self[tag]
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Protobuf
|
2
|
+
module Protoable
|
3
|
+
def defined_filenames
|
4
|
+
@defined_filenames ||= []
|
5
|
+
end
|
6
|
+
|
7
|
+
def defined_in(filename)
|
8
|
+
defined_filenames << File.expand_path(filename)
|
9
|
+
end
|
10
|
+
|
11
|
+
def proto_filenames
|
12
|
+
defined_filenames.map do |filename|
|
13
|
+
retrieve_header(File.read(filename)).first
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def proto_contents
|
18
|
+
#TODO: temporary implementation because the result includes not only this message but also all messages
|
19
|
+
ret = {}
|
20
|
+
defined_filenames.map do |filename|
|
21
|
+
header = retrieve_header File.read(filename)
|
22
|
+
ret[header.first] = header.last
|
23
|
+
end
|
24
|
+
ret
|
25
|
+
end
|
26
|
+
|
27
|
+
def retrieve_header(contents)
|
28
|
+
if contents =~ /### Generated by rprotoc\. DO NOT EDIT!\n### <proto file: (.*)>\n((# .*\n)+)/
|
29
|
+
proto_filename = $1
|
30
|
+
proto_contents = $2.gsub(/^# /, '')
|
31
|
+
[proto_filename, proto_contents]
|
32
|
+
else
|
33
|
+
[nil, nil]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Rpc
|
5
|
+
class Client
|
6
|
+
def initialize(host, port)
|
7
|
+
@host, @port = host, port
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(name, request, response)
|
11
|
+
socket = TCPSocket.open @host, @port
|
12
|
+
socket.write "#{name}\n"
|
13
|
+
request.serialize_to socket
|
14
|
+
socket.close_write
|
15
|
+
response.parse_from socket
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Protobuf
|
2
|
+
module Rpc
|
3
|
+
class Handler
|
4
|
+
class <<self
|
5
|
+
attr_reader :request_class, :response_class
|
6
|
+
|
7
|
+
def request(request_class)
|
8
|
+
@request_class = request_class
|
9
|
+
end
|
10
|
+
|
11
|
+
def response(response_class)
|
12
|
+
@response_class = response_class
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'webrick/config'
|
2
|
+
require 'webrick/server'
|
3
|
+
|
4
|
+
module Protobuf
|
5
|
+
module Rpc
|
6
|
+
class Server < WEBrick::GenericServer
|
7
|
+
def initialize(config={:Port => 9999}, default=WEBrick::Config::General)
|
8
|
+
super config, default
|
9
|
+
setup_handlers
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup_handlers
|
13
|
+
@handlers = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_handler(socket)
|
17
|
+
@handlers[socket.readline.strip.to_sym]
|
18
|
+
end
|
19
|
+
|
20
|
+
def run(socket)
|
21
|
+
handler = get_handler socket
|
22
|
+
request = handler.request_class.new
|
23
|
+
request.parse_from socket
|
24
|
+
response = handler.response_class.new
|
25
|
+
begin
|
26
|
+
handler.process_request request, response
|
27
|
+
rescue StandardError => ex
|
28
|
+
@logger.error ex
|
29
|
+
ensure
|
30
|
+
begin
|
31
|
+
response.serialize_to socket
|
32
|
+
rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN => ex
|
33
|
+
@logger.error ex
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/test/addressbook.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
### Generated by rprotoc. DO NOT EDIT!
|
2
|
+
### <proto file: test/addressbook.proto>
|
3
|
+
# package tutorial;
|
4
|
+
#
|
5
|
+
# message Person {
|
6
|
+
# required string name = 1;
|
7
|
+
# required int32 id = 2;
|
8
|
+
# optional string email = 3;
|
9
|
+
#
|
10
|
+
# enum PhoneType {
|
11
|
+
# MOBILE = 0;
|
12
|
+
# HOME = 1;
|
13
|
+
# WORK = 2;
|
14
|
+
# }
|
15
|
+
#
|
16
|
+
# message PhoneNumber {
|
17
|
+
# required string number = 1;
|
18
|
+
# optional PhoneType type = 2 [default = HOME];
|
19
|
+
# }
|
20
|
+
#
|
21
|
+
# repeated PhoneNumber phone = 4;
|
22
|
+
#
|
23
|
+
# extensions 100 to 200;
|
24
|
+
# }
|
25
|
+
#
|
26
|
+
# extend Person {
|
27
|
+
# optional int32 age = 100;
|
28
|
+
# }
|
29
|
+
#
|
30
|
+
# message AddressBook {
|
31
|
+
# repeated Person person = 1;
|
32
|
+
# }
|
33
|
+
require 'protobuf/message/message'
|
34
|
+
require 'protobuf/message/enum'
|
35
|
+
require 'protobuf/message/service'
|
36
|
+
require 'protobuf/message/extend'
|
37
|
+
|
38
|
+
module Tutorial
|
39
|
+
|
40
|
+
class Person < ::Protobuf::Message
|
41
|
+
defined_in __FILE__
|
42
|
+
required :string, :name, 1
|
43
|
+
required :int32, :id, 2
|
44
|
+
optional :string, :email, 3
|
45
|
+
|
46
|
+
class PhoneType < ::Protobuf::Enum
|
47
|
+
defined_in __FILE__
|
48
|
+
MOBILE = 0
|
49
|
+
HOME = 1
|
50
|
+
WORK = 2
|
51
|
+
end
|
52
|
+
|
53
|
+
class PhoneNumber < ::Protobuf::Message
|
54
|
+
defined_in __FILE__
|
55
|
+
required :string, :number, 1
|
56
|
+
optional :PhoneType, :type, 2, {:default => :HOME}
|
57
|
+
end
|
58
|
+
|
59
|
+
repeated :PhoneNumber, :phone, 4
|
60
|
+
|
61
|
+
#extensions 100..200
|
62
|
+
end
|
63
|
+
|
64
|
+
# see: addressbool_ext.rb
|
65
|
+
#class Person < ::Protobuf::Message
|
66
|
+
# optional :int32, :age, 100, :extension => true
|
67
|
+
#end
|
68
|
+
|
69
|
+
class AddressBook < ::Protobuf::Message
|
70
|
+
defined_in __FILE__
|
71
|
+
repeated :Person, :person, 1
|
72
|
+
end
|
73
|
+
|
74
|
+
#class SearchService < Protobuf::Service
|
75
|
+
# rpc :Search, :request => :SearchRequest, :response => :SearchResponse
|
76
|
+
#end
|
77
|
+
|
78
|
+
#Protobuf::OPTIONS[:optimize_for] = :SPEED
|
79
|
+
#Protobuf::OPTIONS[:java_package] = :'com.example.foo'
|
80
|
+
end
|
81
|
+
|
82
|
+
=begin
|
83
|
+
tutorial = Object.const_set :Tutorial, Module.new
|
84
|
+
person = tutorial.const_set :Person, Class.new(Protobuf::Message)
|
85
|
+
person.required :string, :name, 1
|
86
|
+
person.required :int32, :id, 2
|
87
|
+
person.optional :string, :email, 3
|
88
|
+
phone_type = person.const_set :PhoneType, Class.new(Protobuf::Enum)
|
89
|
+
phone_type.const_set :MOBILE, 0
|
90
|
+
phone_type.const_set :HOME, 1
|
91
|
+
phone_type.const_set :WORK, 2
|
92
|
+
phone_number = person.const_set :PhoneNumber, Class.new(Protobuf::Message)
|
93
|
+
phone_number.required :string, :number, 1
|
94
|
+
phone_number.optional :PhoneType, :type, 2, {:default => :HOME}
|
95
|
+
person.repeated :PhoneNumber, :phone, 4
|
96
|
+
address_book = tutorial.const_set :AddressBook, Class.new(Protobuf::Message)
|
97
|
+
address_book.repeated :Person, :person, 1
|
98
|
+
=end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'protobuf/message/message'
|
2
|
+
require 'protobuf/message/enum'
|
3
|
+
require 'protobuf/message/service'
|
4
|
+
require 'protobuf/message/extend'
|
5
|
+
|
6
|
+
module TutorialExt
|
7
|
+
|
8
|
+
class Person < ::Protobuf::Message
|
9
|
+
required :string, :name, 1
|
10
|
+
required :int32, :id, 2
|
11
|
+
optional :string, :email, 3
|
12
|
+
|
13
|
+
class PhoneType < ::Protobuf::Enum
|
14
|
+
MOBILE = 0
|
15
|
+
HOME = 1
|
16
|
+
WORK = 2
|
17
|
+
end
|
18
|
+
|
19
|
+
class PhoneNumber < ::Protobuf::Message
|
20
|
+
required :string, :number, 1
|
21
|
+
optional :PhoneType, :type, 2, {:default => :HOME}
|
22
|
+
end
|
23
|
+
|
24
|
+
repeated :PhoneNumber, :phone, 4
|
25
|
+
|
26
|
+
extensions 100..200
|
27
|
+
end
|
28
|
+
|
29
|
+
# see: addressbool_ext.rb
|
30
|
+
#class Person < ::Protobuf::Message
|
31
|
+
# optional :int32, :age, 100, :extension => true
|
32
|
+
#end
|
33
|
+
|
34
|
+
class AddressBook < ::Protobuf::Message
|
35
|
+
repeated :Person, :person, 1
|
36
|
+
end
|
37
|
+
|
38
|
+
#class SearchService < Protobuf::Service
|
39
|
+
# rpc :Search => :SearchRequest, :returns => :SearchResponse
|
40
|
+
#end
|
41
|
+
|
42
|
+
#Protobuf::OPTIONS[:optimize_for] = :SPEED
|
43
|
+
#Protobuf::OPTIONS[:java_package] = :'com.example.foo'
|
44
|
+
end
|
45
|
+
|
46
|
+
=begin
|
47
|
+
tutorial = Object.const_set :Tutorial, Module.new
|
48
|
+
person = tutorial.const_set :Person, Class.new(Protobuf::Message)
|
49
|
+
person.required :string, :name, 1
|
50
|
+
person.required :int32, :id, 2
|
51
|
+
person.optional :string, :email, 3
|
52
|
+
phone_type = person.const_set :PhoneType, Class.new(Protobuf::Enum)
|
53
|
+
phone_type.const_set :MOBILE, 0
|
54
|
+
phone_type.const_set :HOME, 1
|
55
|
+
phone_type.const_set :WORK, 2
|
56
|
+
phone_number = person.const_set :PhoneNumber, Class.new(Protobuf::Message)
|
57
|
+
phone_number.required :string, :number, 1
|
58
|
+
phone_number.optional :PhoneType, :type, 2, {:default => :HOME}
|
59
|
+
person.repeated :PhoneNumber, :phone, 4
|
60
|
+
address_book = tutorial.const_set :AddressBook, Class.new(Protobuf::Message)
|
61
|
+
address_book.repeated :Person, :person, 1
|
62
|
+
=end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'protobuf/message/message'
|
2
|
+
require 'protobuf/message/enum'
|
3
|
+
require 'protobuf/message/service'
|
4
|
+
require 'protobuf/message/extend'
|
5
|
+
|
6
|
+
require 'addressbook_base'
|
7
|
+
|
8
|
+
module TutorialExt
|
9
|
+
class Person < ::Protobuf::Message
|
10
|
+
optional :int32, :age, 100, :extension => true
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.push "#{File.dirname(__FILE__)}/../lib"
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
require 'protobuf/descriptor/descriptor_builder'
|
7
|
+
require 'protobuf/descriptor/descriptor_proto'
|
8
|
+
|
9
|
+
class DescriptorTest < Test::Unit::TestCase
|
10
|
+
def test_unbuild
|
11
|
+
tutorial_proto = Google::Protobuf::FileDescriptorProto.new
|
12
|
+
tutorial_proto.parse_from_file 'person.bin'
|
13
|
+
Protobuf::Descriptor::DescriptorBuilder.build tutorial_proto
|
14
|
+
|
15
|
+
assert_nothing_raised {Tutorial::Person}
|
16
|
+
assert_nothing_raised {Tutorial::Person.new}
|
17
|
+
assert_equal ['email', 'id', 'name', 'phone'],
|
18
|
+
Tutorial::Person.fields.map{|tag, field| field.name}.sort
|
19
|
+
|
20
|
+
assert_nothing_raised {Tutorial::Person::PhoneNumber}
|
21
|
+
assert_nothing_raised {Tutorial::Person::PhoneNumber.new}
|
22
|
+
assert_equal ['number', 'type'],
|
23
|
+
Tutorial::Person::PhoneNumber.fields.map{|tag, field| field.name}.sort
|
24
|
+
|
25
|
+
assert_nothing_raised {Tutorial::Person::PhoneType}
|
26
|
+
assert_equal 0, Tutorial::Person::PhoneType::MOBILE
|
27
|
+
assert_equal 1, Tutorial::Person::PhoneType::HOME
|
28
|
+
assert_equal 2, Tutorial::Person::PhoneType::WORK
|
29
|
+
end
|
30
|
+
end
|
data/test/collision.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
### Generated by rprotoc. DO NOT EDIT!
|
2
|
+
### <proto file: test/proto/collision.proto>
|
3
|
+
# message CollisionTest {
|
4
|
+
# optional string a = 1;
|
5
|
+
# optional string b = 1;
|
6
|
+
# }
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'protobuf/message/message'
|
10
|
+
require 'protobuf/message/enum'
|
11
|
+
require 'protobuf/message/service'
|
12
|
+
require 'protobuf/message/extend'
|
13
|
+
|
14
|
+
class CollisionTest < ::Protobuf::Message
|
15
|
+
defined_in __FILE__
|
16
|
+
optional :string, :a, 1
|
17
|
+
optional :string, :b, 1
|
18
|
+
end
|
data/test/data/data.bin
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
import addressbook_pb2
|
2
|
+
import sys
|
3
|
+
|
4
|
+
person = addressbook_pb2.Person()
|
5
|
+
person.id = 1234
|
6
|
+
person.name = "John Doe"
|
7
|
+
person.email = "jdoe@example.com"
|
8
|
+
phone = person.phone.add()
|
9
|
+
phone.number = "555-4321"
|
10
|
+
phone.type = addressbook_pb2.Person.HOME
|
11
|
+
|
12
|
+
f = open('data.bin', 'wb')
|
13
|
+
f.write(person.SerializeToString())
|
14
|
+
f.close()
|
data/test/data/types.bin
ADDED
Binary file
|