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