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.
Files changed (76) hide show
  1. data/History.txt +14 -0
  2. data/Manifest.txt +74 -0
  3. data/README.txt +58 -0
  4. data/Rakefile +18 -0
  5. data/bin/mk_parser +2 -0
  6. data/bin/rprotoc +36 -0
  7. data/examples/addressbook.pb.rb +56 -0
  8. data/examples/addressbook.proto +24 -0
  9. data/examples/reading_a_message.rb +32 -0
  10. data/examples/writing_a_message.rb +46 -0
  11. data/lib/protobuf/common/wire_type.rb +10 -0
  12. data/lib/protobuf/compiler/compiler.rb +54 -0
  13. data/lib/protobuf/compiler/nodes.rb +319 -0
  14. data/lib/protobuf/compiler/proto.y +203 -0
  15. data/lib/protobuf/compiler/proto2.ebnf +79 -0
  16. data/lib/protobuf/compiler/proto_parser.rb +1394 -0
  17. data/lib/protobuf/compiler/template/rpc_bin.erb +4 -0
  18. data/lib/protobuf/compiler/template/rpc_client.erb +18 -0
  19. data/lib/protobuf/compiler/template/rpc_service.erb +25 -0
  20. data/lib/protobuf/compiler/visitors.rb +288 -0
  21. data/lib/protobuf/descriptor/descriptor.proto +286 -0
  22. data/lib/protobuf/descriptor/descriptor.rb +54 -0
  23. data/lib/protobuf/descriptor/descriptor_builder.rb +144 -0
  24. data/lib/protobuf/descriptor/descriptor_proto.rb +119 -0
  25. data/lib/protobuf/descriptor/enum_descriptor.rb +33 -0
  26. data/lib/protobuf/descriptor/field_descriptor.rb +50 -0
  27. data/lib/protobuf/descriptor/file_descriptor.rb +38 -0
  28. data/lib/protobuf/message/decoder.rb +93 -0
  29. data/lib/protobuf/message/encoder.rb +37 -0
  30. data/lib/protobuf/message/enum.rb +28 -0
  31. data/lib/protobuf/message/extend.rb +8 -0
  32. data/lib/protobuf/message/field.rb +654 -0
  33. data/lib/protobuf/message/message.rb +308 -0
  34. data/lib/protobuf/message/protoable.rb +37 -0
  35. data/lib/protobuf/message/service.rb +9 -0
  36. data/lib/protobuf/rpc/client.rb +19 -0
  37. data/lib/protobuf/rpc/handler.rb +17 -0
  38. data/lib/protobuf/rpc/server.rb +39 -0
  39. data/lib/ruby_protobuf.rb +3 -0
  40. data/test/addressbook.rb +98 -0
  41. data/test/addressbook_base.rb +62 -0
  42. data/test/addressbook_ext.rb +12 -0
  43. data/test/check_unbuild.rb +30 -0
  44. data/test/collision.rb +18 -0
  45. data/test/data/data.bin +3 -0
  46. data/test/data/data_source.py +14 -0
  47. data/test/data/types.bin +0 -0
  48. data/test/data/types_source.py +22 -0
  49. data/test/data/unk.png +0 -0
  50. data/test/ext_collision.rb +25 -0
  51. data/test/ext_range.rb +23 -0
  52. data/test/merge.rb +40 -0
  53. data/test/nested.rb +25 -0
  54. data/test/proto/addressbook.proto +31 -0
  55. data/test/proto/addressbook_base.proto +26 -0
  56. data/test/proto/addressbook_ext.proto +6 -0
  57. data/test/proto/collision.proto +5 -0
  58. data/test/proto/ext_collision.proto +8 -0
  59. data/test/proto/ext_range.proto +7 -0
  60. data/test/proto/merge.proto +15 -0
  61. data/test/proto/nested.proto +7 -0
  62. data/test/proto/rpc.proto +6 -0
  63. data/test/proto/types.proto +17 -0
  64. data/test/test_addressbook.rb +43 -0
  65. data/test/test_compiler.rb +313 -0
  66. data/test/test_descriptor.rb +122 -0
  67. data/test/test_extension.rb +40 -0
  68. data/test/test_message.rb +106 -0
  69. data/test/test_optional_field.rb +68 -0
  70. data/test/test_parse.rb +15 -0
  71. data/test/test_ruby_protobuf.rb +1 -0
  72. data/test/test_serialize.rb +42 -0
  73. data/test/test_standard_message.rb +96 -0
  74. data/test/test_types.rb +181 -0
  75. data/test/types.rb +22 -0
  76. metadata +150 -0
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require '<%= underscored_name %>'
3
+
4
+ <%= module_name %>::<%= service_name %>.new(:port => <%= default_port %>).start
@@ -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
+