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,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'protobuf/rpc/client'
|
3
|
+
require '<%= required_file %>'
|
4
|
+
|
5
|
+
# build request
|
6
|
+
request = <%= message_module %>::<%= request %>.new
|
7
|
+
# TODO: setup a request
|
8
|
+
raise StandardError.new('setup a request')
|
9
|
+
|
10
|
+
# create blunk response
|
11
|
+
response = <%= message_module %>::<%= response %>.new
|
12
|
+
|
13
|
+
# execute rpc
|
14
|
+
Protobuf::Rpc::Client.new('localhost', <%= default_port %>).call :<%= underscore name %>, request, response
|
15
|
+
|
16
|
+
# show response
|
17
|
+
puts response
|
18
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'protobuf/rpc/server'
|
2
|
+
require 'protobuf/rpc/handler'
|
3
|
+
require '<%= required_file %>'
|
4
|
+
|
5
|
+
<%- rpcs.each do |name, request, response| -%>
|
6
|
+
class <%= module_name %>::<%= name %>Handler < Protobuf::Rpc::Handler
|
7
|
+
request <%= module_name %>::<%= request %>
|
8
|
+
response <%= module_name %>::<%= response %>
|
9
|
+
|
10
|
+
def self.process_request(request, response)
|
11
|
+
# TODO: edit this method
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
<%- end -%>
|
16
|
+
class <%= module_name %>::<%= service_name %> < Protobuf::Rpc::Server
|
17
|
+
def setup_handlers
|
18
|
+
@handlers = {
|
19
|
+
<%- rpcs.each do |name, | -%>
|
20
|
+
:<%= underscore name %> => <%= module_name %>::<%= name %>Handler,
|
21
|
+
<%- end -%>
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,288 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'protobuf/descriptor/descriptor_proto'
|
4
|
+
|
5
|
+
module Protobuf
|
6
|
+
module Visitor
|
7
|
+
class Base
|
8
|
+
attr_reader :silent
|
9
|
+
|
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='.')
|
39
|
+
@proto_dir, @out_dir = proto_dir, out_dir
|
40
|
+
@indent = 0
|
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
|
+
if proto_file
|
52
|
+
proto_filepath = File.exist?(proto_file) ?
|
53
|
+
proto_file : "#{@proto_dir}/#{proto_file}"
|
54
|
+
File.read(proto_filepath).gsub(/^/, '# ')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def write(str)
|
59
|
+
ruby << "#{' ' * @indent}#{str}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def increment
|
63
|
+
@indent += 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def decrement
|
67
|
+
@indent -= 1
|
68
|
+
end
|
69
|
+
|
70
|
+
def close_ruby
|
71
|
+
while 0 < indent
|
72
|
+
decrement
|
73
|
+
write 'end'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def ruby
|
78
|
+
@ruby ||= []
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_s
|
82
|
+
@ruby.join "\n"
|
83
|
+
end
|
84
|
+
|
85
|
+
def in_context(klass, &block)
|
86
|
+
increment
|
87
|
+
context.push klass
|
88
|
+
block.call
|
89
|
+
context.pop
|
90
|
+
decrement
|
91
|
+
end
|
92
|
+
|
93
|
+
def visit(node)
|
94
|
+
node.accept_message_visitor self
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
def required_message_from_proto(proto_file)
|
99
|
+
rb_path = proto_file.sub(/\.proto$/, '.pb.rb')
|
100
|
+
unless File.exist?("#{@out_dir}/#{rb_path}")
|
101
|
+
Compiler.compile proto_file, @proto_dir, @out_dir
|
102
|
+
end
|
103
|
+
rb_path.sub(/\.rb$/, '')
|
104
|
+
end
|
105
|
+
|
106
|
+
def create_files(filename, out_dir, file_create)
|
107
|
+
eval to_s # check the message
|
108
|
+
if file_create
|
109
|
+
log_writing filename
|
110
|
+
FileUtils.mkpath File.dirname(filename)
|
111
|
+
File.open(filename, 'w') {|file| file.write to_s}
|
112
|
+
else
|
113
|
+
to_s
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class CreateRpcVisitor < Base
|
119
|
+
attr_accessor :package, :services, :current_service, :file_contents
|
120
|
+
|
121
|
+
def initialize
|
122
|
+
@services = {}
|
123
|
+
@create_file = true
|
124
|
+
@file_contents = {}
|
125
|
+
end
|
126
|
+
|
127
|
+
def visit(node)
|
128
|
+
node.accept_rpc_visitor self
|
129
|
+
self
|
130
|
+
end
|
131
|
+
|
132
|
+
def add_rpc(name, request, response)
|
133
|
+
(@services[@current_service] ||= []) << [name, request.first, response.first]
|
134
|
+
end
|
135
|
+
|
136
|
+
def create_files(message_file, out_dir, create_file=true)
|
137
|
+
@create_file = create_file
|
138
|
+
default_port = 9999
|
139
|
+
@services.each do |service_name, rpcs|
|
140
|
+
underscored_name = underscore service_name.to_s
|
141
|
+
message_module = package.map{|p| p.to_s.capitalize}.join('::')
|
142
|
+
required_file = message_file.sub(/^\.\//, '').sub(/\.rb$/, '')
|
143
|
+
|
144
|
+
create_bin out_dir, underscored_name, message_module, service_name, default_port
|
145
|
+
create_service message_file, out_dir, underscored_name, message_module,
|
146
|
+
service_name, default_port, rpcs, required_file
|
147
|
+
rpcs.each do |name, request, response|
|
148
|
+
create_client out_dir, underscored_name, default_port, name, request, response,
|
149
|
+
message_module, required_file
|
150
|
+
end
|
151
|
+
end
|
152
|
+
@file_contents
|
153
|
+
end
|
154
|
+
|
155
|
+
def create_bin(out_dir, underscored_name, module_name, service_name, default_port)
|
156
|
+
bin_filename = "#{out_dir}/start_#{underscored_name}"
|
157
|
+
bin_contents = template_erb('rpc_bin').result binding
|
158
|
+
create_file_with_backup bin_filename, bin_contents, true if @create_file
|
159
|
+
@file_contents[bin_filename] = bin_contents
|
160
|
+
end
|
161
|
+
|
162
|
+
def create_service(message_file, out_dir, underscored_name, module_name, service_name,
|
163
|
+
default_port, rpcs, required_file)
|
164
|
+
service_filename = "#{out_dir}/#{underscored_name}.rb"
|
165
|
+
service_contents = template_erb('rpc_service').result binding
|
166
|
+
create_file_with_backup service_filename, service_contents if @create_file
|
167
|
+
@file_contents[service_filename] = service_contents
|
168
|
+
end
|
169
|
+
|
170
|
+
def create_client(out_dir, underscored_name, default_port, name, request, response,
|
171
|
+
message_module, required_file)
|
172
|
+
client_filename = "#{out_dir}/client_#{underscore name}.rb"
|
173
|
+
client_contents = template_erb('rpc_client').result binding
|
174
|
+
create_file_with_backup client_filename, client_contents, true if @create_file
|
175
|
+
@file_contents[client_filename] = client_contents
|
176
|
+
end
|
177
|
+
|
178
|
+
private
|
179
|
+
|
180
|
+
def underscore(str)
|
181
|
+
str.to_s.gsub(/\B[A-Z]/, '_\&').downcase
|
182
|
+
end
|
183
|
+
|
184
|
+
def template_erb(template)
|
185
|
+
ERB.new File.read("#{File.dirname(__FILE__)}/template/#{template}.erb"), nil, '-'
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
class CreateDescriptorVisitor < Base
|
190
|
+
attr_reader :file_descriptor
|
191
|
+
attr_accessor :filename
|
192
|
+
|
193
|
+
def initialize(filename=nil)
|
194
|
+
@context = []
|
195
|
+
@filename = filename
|
196
|
+
end
|
197
|
+
|
198
|
+
def visit(node)
|
199
|
+
node.accept_descriptor_visitor self
|
200
|
+
self
|
201
|
+
end
|
202
|
+
|
203
|
+
def in_context(descriptor, &block)
|
204
|
+
@context.push descriptor
|
205
|
+
block.call
|
206
|
+
@context.pop
|
207
|
+
end
|
208
|
+
|
209
|
+
def current_descriptor
|
210
|
+
@context.last
|
211
|
+
end
|
212
|
+
|
213
|
+
def file_descriptor=(descriptor)
|
214
|
+
@file_descriptor = descriptor
|
215
|
+
@file_descriptor.name = @filename
|
216
|
+
end
|
217
|
+
|
218
|
+
def add_option(name, value)
|
219
|
+
options =
|
220
|
+
case current_descriptor
|
221
|
+
when Google::Protobuf::FileDescriptorProto
|
222
|
+
Google::Protobuf::FileOptions.new
|
223
|
+
when Google::Protobuf::DescriptorProto
|
224
|
+
Google::Protobuf::MessageOptions.new
|
225
|
+
when Google::Protobuf::FieldDescriptorProto
|
226
|
+
Google::Protobuf::FieldOptions.new
|
227
|
+
when Google::Protobuf::EnumDescriptorProto
|
228
|
+
Google::Protobuf::EnumOptions.new
|
229
|
+
when Google::Protobuf::EnumValueDescriptorProto
|
230
|
+
Google::Protobuf::EnumValueOptions.new
|
231
|
+
when Google::Protobuf::ServiceDescriptorProto
|
232
|
+
Google::Protobuf::ServiceOptions.new
|
233
|
+
when Google::Protobuf::MethodDescriptorProto
|
234
|
+
Google::Protobuf::MethodOptions.new
|
235
|
+
else
|
236
|
+
raise ArgumentError.new('Invalid context')
|
237
|
+
end
|
238
|
+
#TODO how should options be handled?
|
239
|
+
#current_descriptor.options << option
|
240
|
+
end
|
241
|
+
|
242
|
+
def descriptor=(descriptor)
|
243
|
+
case current_descriptor
|
244
|
+
when Google::Protobuf::FileDescriptorProto
|
245
|
+
current_descriptor.message_type << descriptor
|
246
|
+
when Google::Protobuf::DescriptorProto
|
247
|
+
current_descriptor.nested_type << descriptor
|
248
|
+
else
|
249
|
+
raise ArgumentError.new('Invalid context')
|
250
|
+
end
|
251
|
+
end
|
252
|
+
alias message_descriptor= descriptor=
|
253
|
+
|
254
|
+
def enum_descriptor=(descriptor)
|
255
|
+
current_descriptor.enum_type << descriptor
|
256
|
+
end
|
257
|
+
|
258
|
+
def enum_value_descriptor=(descriptor)
|
259
|
+
current_descriptor.value << descriptor
|
260
|
+
end
|
261
|
+
|
262
|
+
def service_descriptor=(descriptor)
|
263
|
+
current_descriptor.service << descriptor
|
264
|
+
end
|
265
|
+
|
266
|
+
def method_descriptor=(descriptor)
|
267
|
+
current_descriptor.method << descriptor
|
268
|
+
end
|
269
|
+
|
270
|
+
def field_descriptor=(descriptor)
|
271
|
+
case current_descriptor
|
272
|
+
when Google::Protobuf::FileDescriptorProto
|
273
|
+
current_descriptor.extension << descriptor
|
274
|
+
when Google::Protobuf::DescriptorProto
|
275
|
+
current_descriptor.field << descriptor
|
276
|
+
#TODO: how should i distiguish between field and extension
|
277
|
+
#current_descriptor.extension << descriptor
|
278
|
+
else
|
279
|
+
raise ArgumentError.new('Invalid context')
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def extension_range_descriptor=(descriptor)
|
284
|
+
current_descriptor.extension_range << descriptor
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
@@ -0,0 +1,286 @@
|
|
1
|
+
// Protocol Buffers - Google's data interchange format
|
2
|
+
// Copyright 2008 Google Inc.
|
3
|
+
// http://code.google.com/p/protobuf/
|
4
|
+
//
|
5
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
// you may not use this file except in compliance with the License.
|
7
|
+
// You may obtain a copy of the License at
|
8
|
+
//
|
9
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
//
|
11
|
+
// Unless required by applicable law or agreed to in writing, software
|
12
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
// See the License for the specific language governing permissions and
|
15
|
+
// limitations under the License.
|
16
|
+
|
17
|
+
// Author: kenton@google.com (Kenton Varda)
|
18
|
+
// Based on original Protocol Buffers design by
|
19
|
+
// Sanjay Ghemawat, Jeff Dean, and others.
|
20
|
+
//
|
21
|
+
// The messages in this file describe the definitions found in .proto files.
|
22
|
+
// A valid .proto file can be translated directly to a FileDescriptorProto
|
23
|
+
// without any other information (e.g. without reading its imports).
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
package google.protobuf;
|
28
|
+
option java_package = "com.google.protobuf";
|
29
|
+
option java_outer_classname = "DescriptorProtos";
|
30
|
+
|
31
|
+
// descriptor.proto must be optimized for speed because reflection-based
|
32
|
+
// algorithms don't work during bootstrapping.
|
33
|
+
option optimize_for = SPEED;
|
34
|
+
|
35
|
+
// Describes a complete .proto file.
|
36
|
+
message FileDescriptorProto {
|
37
|
+
optional string name = 1; // file name, relative to root of source tree
|
38
|
+
optional string package = 2; // e.g. "foo", "foo.bar", etc.
|
39
|
+
|
40
|
+
// Names of files imported by this file.
|
41
|
+
repeated string dependency = 3;
|
42
|
+
|
43
|
+
// All top-level definitions in this file.
|
44
|
+
repeated DescriptorProto message_type = 4;
|
45
|
+
repeated EnumDescriptorProto enum_type = 5;
|
46
|
+
repeated ServiceDescriptorProto service = 6;
|
47
|
+
repeated FieldDescriptorProto extension = 7;
|
48
|
+
|
49
|
+
optional FileOptions options = 8;
|
50
|
+
}
|
51
|
+
|
52
|
+
// Describes a message type.
|
53
|
+
message DescriptorProto {
|
54
|
+
optional string name = 1;
|
55
|
+
|
56
|
+
repeated FieldDescriptorProto field = 2;
|
57
|
+
repeated FieldDescriptorProto extension = 6;
|
58
|
+
|
59
|
+
repeated DescriptorProto nested_type = 3;
|
60
|
+
repeated EnumDescriptorProto enum_type = 4;
|
61
|
+
|
62
|
+
message ExtensionRange {
|
63
|
+
optional int32 start = 1;
|
64
|
+
optional int32 end = 2;
|
65
|
+
}
|
66
|
+
repeated ExtensionRange extension_range = 5;
|
67
|
+
|
68
|
+
optional MessageOptions options = 7;
|
69
|
+
}
|
70
|
+
|
71
|
+
// Describes a field within a message.
|
72
|
+
message FieldDescriptorProto {
|
73
|
+
enum Type {
|
74
|
+
// 0 is reserved for errors.
|
75
|
+
// Order is weird for historical reasons.
|
76
|
+
TYPE_DOUBLE = 1;
|
77
|
+
TYPE_FLOAT = 2;
|
78
|
+
TYPE_INT64 = 3; // Not ZigZag encoded. Negative numbers
|
79
|
+
// take 10 bytes. Use TYPE_SINT64 if negative
|
80
|
+
// values are likely.
|
81
|
+
TYPE_UINT64 = 4;
|
82
|
+
TYPE_INT32 = 5; // Not ZigZag encoded. Negative numbers
|
83
|
+
// take 10 bytes. Use TYPE_SINT32 if negative
|
84
|
+
// values are likely.
|
85
|
+
TYPE_FIXED64 = 6;
|
86
|
+
TYPE_FIXED32 = 7;
|
87
|
+
TYPE_BOOL = 8;
|
88
|
+
TYPE_STRING = 9;
|
89
|
+
TYPE_GROUP = 10; // Tag-delimited aggregate.
|
90
|
+
TYPE_MESSAGE = 11; // Length-delimited aggregate.
|
91
|
+
|
92
|
+
// New in version 2.
|
93
|
+
TYPE_BYTES = 12;
|
94
|
+
TYPE_UINT32 = 13;
|
95
|
+
TYPE_ENUM = 14;
|
96
|
+
TYPE_SFIXED32 = 15;
|
97
|
+
TYPE_SFIXED64 = 16;
|
98
|
+
TYPE_SINT32 = 17; // Uses ZigZag encoding.
|
99
|
+
TYPE_SINT64 = 18; // Uses ZigZag encoding.
|
100
|
+
};
|
101
|
+
|
102
|
+
enum Label {
|
103
|
+
// 0 is reserved for errors
|
104
|
+
LABEL_OPTIONAL = 1;
|
105
|
+
LABEL_REQUIRED = 2;
|
106
|
+
LABEL_REPEATED = 3;
|
107
|
+
// TODO(sanjay): Should we add LABEL_MAP?
|
108
|
+
};
|
109
|
+
|
110
|
+
optional string name = 1;
|
111
|
+
optional int32 number = 3;
|
112
|
+
optional Label label = 4;
|
113
|
+
|
114
|
+
// If type_name is set, this need not be set. If both this and type_name
|
115
|
+
// are set, this must be either TYPE_ENUM or TYPE_MESSAGE.
|
116
|
+
optional Type type = 5;
|
117
|
+
|
118
|
+
// For message and enum types, this is the name of the type. If the name
|
119
|
+
// starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
|
120
|
+
// rules are used to find the type (i.e. first the nested types within this
|
121
|
+
// message are searched, then within the parent, on up to the root
|
122
|
+
// namespace).
|
123
|
+
optional string type_name = 6;
|
124
|
+
|
125
|
+
// For extensions, this is the name of the type being extended. It is
|
126
|
+
// resolved in the same manner as type_name.
|
127
|
+
optional string extendee = 2;
|
128
|
+
|
129
|
+
// For numeric types, contains the original text representation of the value.
|
130
|
+
// For booleans, "true" or "false".
|
131
|
+
// For strings, contains the default text contents (not escaped in any way).
|
132
|
+
// For bytes, contains the C escaped value. All bytes >= 128 are escaped.
|
133
|
+
// TODO(kenton): Base-64 encode?
|
134
|
+
optional string default_value = 7;
|
135
|
+
|
136
|
+
optional FieldOptions options = 8;
|
137
|
+
}
|
138
|
+
|
139
|
+
// Describes an enum type.
|
140
|
+
message EnumDescriptorProto {
|
141
|
+
optional string name = 1;
|
142
|
+
|
143
|
+
repeated EnumValueDescriptorProto value = 2;
|
144
|
+
|
145
|
+
optional EnumOptions options = 3;
|
146
|
+
}
|
147
|
+
|
148
|
+
// Describes a value within an enum.
|
149
|
+
message EnumValueDescriptorProto {
|
150
|
+
optional string name = 1;
|
151
|
+
optional int32 number = 2;
|
152
|
+
|
153
|
+
optional EnumValueOptions options = 3;
|
154
|
+
}
|
155
|
+
|
156
|
+
// Describes a service.
|
157
|
+
message ServiceDescriptorProto {
|
158
|
+
optional string name = 1;
|
159
|
+
repeated MethodDescriptorProto method = 2;
|
160
|
+
|
161
|
+
optional ServiceOptions options = 3;
|
162
|
+
}
|
163
|
+
|
164
|
+
// Describes a method of a service.
|
165
|
+
message MethodDescriptorProto {
|
166
|
+
optional string name = 1;
|
167
|
+
|
168
|
+
// Input and output type names. These are resolved in the same way as
|
169
|
+
// FieldDescriptorProto.type_name, but must refer to a message type.
|
170
|
+
optional string input_type = 2;
|
171
|
+
optional string output_type = 3;
|
172
|
+
|
173
|
+
optional MethodOptions options = 4;
|
174
|
+
}
|
175
|
+
|
176
|
+
// ===================================================================
|
177
|
+
// Options
|
178
|
+
|
179
|
+
// Each of the definitions above may have "options" attached. These are
|
180
|
+
// just annotations which may cause code to be generated slightly differently
|
181
|
+
// or may contain hints for code that manipulates protocol messages.
|
182
|
+
|
183
|
+
// TODO(kenton): Allow extensions to options.
|
184
|
+
|
185
|
+
message FileOptions {
|
186
|
+
|
187
|
+
// Sets the Java package where classes generated from this .proto will be
|
188
|
+
// placed. By default, the proto package is used, but this is often
|
189
|
+
// inappropriate because proto packages do not normally start with backwards
|
190
|
+
// domain names.
|
191
|
+
optional string java_package = 1;
|
192
|
+
|
193
|
+
|
194
|
+
// If set, all the classes from the .proto file are wrapped in a single
|
195
|
+
// outer class with the given name. This applies to both Proto1
|
196
|
+
// (equivalent to the old "--one_java_file" option) and Proto2 (where
|
197
|
+
// a .proto always translates to a single class, but you may want to
|
198
|
+
// explicitly choose the class name).
|
199
|
+
optional string java_outer_classname = 8;
|
200
|
+
|
201
|
+
// If set true, then the Java code generator will generate a separate .java
|
202
|
+
// file for each top-level message, enum, and service defined in the .proto
|
203
|
+
// file. Thus, these types will *not* be nested inside the outer class
|
204
|
+
// named by java_outer_classname. However, the outer class will still be
|
205
|
+
// generated to contain the file's getDescriptor() method as well as any
|
206
|
+
// top-level extensions defined in the file.
|
207
|
+
optional bool java_multiple_files = 10 [default=false];
|
208
|
+
|
209
|
+
// Generated classes can be optimized for speed or code size.
|
210
|
+
enum OptimizeMode {
|
211
|
+
SPEED = 1; // Generate complete code for parsing, serialization, etc.
|
212
|
+
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
|
213
|
+
}
|
214
|
+
optional OptimizeMode optimize_for = 9 [default=CODE_SIZE];
|
215
|
+
}
|
216
|
+
|
217
|
+
message MessageOptions {
|
218
|
+
// Set true to use the old proto1 MessageSet wire format for extensions.
|
219
|
+
// This is provided for backwards-compatibility with the MessageSet wire
|
220
|
+
// format. You should not use this for any other reason: It's less
|
221
|
+
// efficient, has fewer features, and is more complicated.
|
222
|
+
//
|
223
|
+
// The message must be defined exactly as follows:
|
224
|
+
// message Foo {
|
225
|
+
// option message_set_wire_format = true;
|
226
|
+
// extensions 4 to max;
|
227
|
+
// }
|
228
|
+
// Note that the message cannot have any defined fields; MessageSets only
|
229
|
+
// have extensions.
|
230
|
+
//
|
231
|
+
// All extensions of your type must be singular messages; e.g. they cannot
|
232
|
+
// be int32s, enums, or repeated messages.
|
233
|
+
//
|
234
|
+
// Because this is an option, the above two restrictions are not enforced by
|
235
|
+
// the protocol compiler.
|
236
|
+
optional bool message_set_wire_format = 1 [default=false];
|
237
|
+
}
|
238
|
+
|
239
|
+
message FieldOptions {
|
240
|
+
// The ctype option instructs the C++ code generator to use a different
|
241
|
+
// representation of the field than it normally would. See the specific
|
242
|
+
// options below. This option is not yet implemented in the open source
|
243
|
+
// release -- sorry, we'll try to include it in a future version!
|
244
|
+
optional CType ctype = 1;
|
245
|
+
enum CType {
|
246
|
+
CORD = 1;
|
247
|
+
|
248
|
+
STRING_PIECE = 2;
|
249
|
+
}
|
250
|
+
|
251
|
+
// EXPERIMENTAL. DO NOT USE.
|
252
|
+
// For "map" fields, the name of the field in the enclosed type that
|
253
|
+
// is the key for this map. For example, suppose we have:
|
254
|
+
// message Item {
|
255
|
+
// required string name = 1;
|
256
|
+
// required string value = 2;
|
257
|
+
// }
|
258
|
+
// message Config {
|
259
|
+
// repeated Item items = 1 [experimental_map_key="name"];
|
260
|
+
// }
|
261
|
+
// In this situation, the map key for Item will be set to "name".
|
262
|
+
// TODO: Fully-implement this, then remove the "experimental_" prefix.
|
263
|
+
optional string experimental_map_key = 9;
|
264
|
+
}
|
265
|
+
|
266
|
+
message EnumOptions {
|
267
|
+
}
|
268
|
+
|
269
|
+
message EnumValueOptions {
|
270
|
+
}
|
271
|
+
|
272
|
+
message ServiceOptions {
|
273
|
+
|
274
|
+
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
275
|
+
// framework. We apologize for hoarding these numbers to ourselves, but
|
276
|
+
// we were already using them long before we decided to release Protocol
|
277
|
+
// Buffers.
|
278
|
+
}
|
279
|
+
|
280
|
+
message MethodOptions {
|
281
|
+
|
282
|
+
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
283
|
+
// framework. We apologize for hoarding these numbers to ourselves, but
|
284
|
+
// we were already using them long before we decided to release Protocol
|
285
|
+
// Buffers.
|
286
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Protobuf
|
2
|
+
module Descriptor
|
3
|
+
class Descriptor
|
4
|
+
def initialize(message_class)
|
5
|
+
@message_class = message_class
|
6
|
+
end
|
7
|
+
|
8
|
+
def proto_type
|
9
|
+
'Google::Protobuf::DescriptorProto'
|
10
|
+
end
|
11
|
+
|
12
|
+
def build(proto, opt={})
|
13
|
+
mod = opt[:module]
|
14
|
+
cls = mod.const_set proto.name, Class.new(@message_class)
|
15
|
+
proto.nested_type.each do |message_proto|
|
16
|
+
Protobuf::Message.descriptor.build message_proto, :module => cls
|
17
|
+
end
|
18
|
+
proto.enum_type.each do |enum_proto|
|
19
|
+
Protobuf::Enum.descriptor.build enum_proto, :module => cls
|
20
|
+
end
|
21
|
+
proto.field.each do |field_proto|
|
22
|
+
Protobuf::Field::BaseField.descriptor.build field_proto, :class => cls
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def unbuild(parent_proto)
|
27
|
+
message_proto = Google::Protobuf::DescriptorProto.new
|
28
|
+
message_proto.name = @message_class.to_s.split('::').last
|
29
|
+
@message_class.fields.each do |tag, field|
|
30
|
+
field.descriptor.unbuild message_proto
|
31
|
+
end
|
32
|
+
ObjectSpace.each_object(Class) do |cls|
|
33
|
+
if innerclass? @message_class, cls
|
34
|
+
cls.descriptor.unbuild message_proto
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
case parent_proto
|
39
|
+
when Google::Protobuf::FileDescriptorProto
|
40
|
+
parent_proto.message_type << message_proto
|
41
|
+
when Google::Protobuf::DescriptorProto
|
42
|
+
parent_proto.nested_type << message_proto
|
43
|
+
else
|
44
|
+
raise TypeError.new(parent_proto.class.name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def innerclass?(parent, child)
|
49
|
+
child.name =~ /::/ and child.name.split('::')[0..-2].join('::') == parent.name
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|