protobuf 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +28 -0
- data/README.md +216 -0
- data/Rakefile +1 -0
- data/bin/rpc_server +117 -0
- data/bin/rprotoc +46 -0
- data/examples/addressbook.pb.rb +55 -0
- data/examples/addressbook.proto +24 -0
- data/examples/reading_a_message.rb +32 -0
- data/examples/writing_a_message.rb +46 -0
- data/lib/protobuf.rb +6 -0
- data/lib/protobuf/common/exceptions.rb +11 -0
- data/lib/protobuf/common/logger.rb +64 -0
- data/lib/protobuf/common/util.rb +59 -0
- data/lib/protobuf/common/wire_type.rb +10 -0
- data/lib/protobuf/compiler/compiler.rb +52 -0
- data/lib/protobuf/compiler/nodes.rb +323 -0
- data/lib/protobuf/compiler/proto.y +216 -0
- data/lib/protobuf/compiler/proto2.ebnf +79 -0
- data/lib/protobuf/compiler/proto_parser.rb +1425 -0
- data/lib/protobuf/compiler/template/rpc_bin.erb +4 -0
- data/lib/protobuf/compiler/template/rpc_client.erb +18 -0
- data/lib/protobuf/compiler/template/rpc_service.erb +25 -0
- data/lib/protobuf/compiler/template/rpc_service_implementation.erb +42 -0
- data/lib/protobuf/compiler/visitors.rb +302 -0
- data/lib/protobuf/descriptor/descriptor.proto +286 -0
- data/lib/protobuf/descriptor/descriptor.rb +55 -0
- data/lib/protobuf/descriptor/descriptor_builder.rb +143 -0
- data/lib/protobuf/descriptor/descriptor_proto.rb +138 -0
- data/lib/protobuf/descriptor/enum_descriptor.rb +33 -0
- data/lib/protobuf/descriptor/field_descriptor.rb +49 -0
- data/lib/protobuf/descriptor/file_descriptor.rb +37 -0
- data/lib/protobuf/message/decoder.rb +83 -0
- data/lib/protobuf/message/encoder.rb +46 -0
- data/lib/protobuf/message/enum.rb +62 -0
- data/lib/protobuf/message/extend.rb +8 -0
- data/lib/protobuf/message/field.rb +701 -0
- data/lib/protobuf/message/message.rb +402 -0
- data/lib/protobuf/message/protoable.rb +38 -0
- data/lib/protobuf/rpc/buffer.rb +74 -0
- data/lib/protobuf/rpc/client.rb +268 -0
- data/lib/protobuf/rpc/client_connection.rb +225 -0
- data/lib/protobuf/rpc/error.rb +34 -0
- data/lib/protobuf/rpc/error/client_error.rb +31 -0
- data/lib/protobuf/rpc/error/server_error.rb +43 -0
- data/lib/protobuf/rpc/rpc.pb.rb +107 -0
- data/lib/protobuf/rpc/server.rb +183 -0
- data/lib/protobuf/rpc/service.rb +244 -0
- data/lib/protobuf/rpc/stat.rb +70 -0
- data/lib/protobuf/version.rb +3 -0
- data/proto/rpc.proto +73 -0
- data/protobuf.gemspec +25 -0
- data/script/mk_parser +2 -0
- data/spec/functional/embedded_service_spec.rb +7 -0
- data/spec/proto/test.pb.rb +31 -0
- data/spec/proto/test.proto +31 -0
- data/spec/proto/test_service.rb +30 -0
- data/spec/proto/test_service_impl.rb +17 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/unit/client_spec.rb +128 -0
- data/spec/unit/common/logger_spec.rb +121 -0
- data/spec/unit/enum_spec.rb +13 -0
- data/spec/unit/message_spec.rb +67 -0
- data/spec/unit/server_spec.rb +27 -0
- data/spec/unit/service_spec.rb +75 -0
- data/test/check_unbuild.rb +30 -0
- data/test/data/data.bin +3 -0
- data/test/data/data_source.py +14 -0
- data/test/data/types.bin +0 -0
- data/test/data/types_source.py +22 -0
- data/test/data/unk.png +0 -0
- data/test/proto/addressbook.pb.rb +66 -0
- data/test/proto/addressbook.proto +33 -0
- data/test/proto/addressbook_base.pb.rb +58 -0
- data/test/proto/addressbook_base.proto +26 -0
- data/test/proto/addressbook_ext.pb.rb +20 -0
- data/test/proto/addressbook_ext.proto +6 -0
- data/test/proto/collision.pb.rb +17 -0
- data/test/proto/collision.proto +5 -0
- data/test/proto/ext_collision.pb.rb +24 -0
- data/test/proto/ext_collision.proto +8 -0
- data/test/proto/ext_range.pb.rb +22 -0
- data/test/proto/ext_range.proto +7 -0
- data/test/proto/float_default.proto +10 -0
- data/test/proto/lowercase.pb.rb +30 -0
- data/test/proto/lowercase.proto +9 -0
- data/test/proto/merge.pb.rb +39 -0
- data/test/proto/merge.proto +15 -0
- data/test/proto/nested.pb.rb +30 -0
- data/test/proto/nested.proto +9 -0
- data/test/proto/optional_field.pb.rb +35 -0
- data/test/proto/optional_field.proto +12 -0
- data/test/proto/packed.pb.rb +22 -0
- data/test/proto/packed.proto +6 -0
- data/test/proto/rpc.proto +6 -0
- data/test/proto/types.pb.rb +84 -0
- data/test/proto/types.proto +37 -0
- data/test/test_addressbook.rb +56 -0
- data/test/test_compiler.rb +325 -0
- data/test/test_descriptor.rb +122 -0
- data/test/test_enum_value.rb +41 -0
- data/test/test_extension.rb +36 -0
- data/test/test_lowercase.rb +11 -0
- data/test/test_message.rb +128 -0
- data/test/test_optional_field.rb +103 -0
- data/test/test_packed_field.rb +40 -0
- data/test/test_parse.rb +15 -0
- data/test/test_repeated_types.rb +132 -0
- data/test/test_serialize.rb +61 -0
- data/test/test_standard_message.rb +96 -0
- data/test/test_types.rb +226 -0
- metadata +261 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package tutorial;
|
|
2
|
+
|
|
3
|
+
message Person {
|
|
4
|
+
required string name = 1;
|
|
5
|
+
required int32 id = 2;
|
|
6
|
+
optional string email = 3;
|
|
7
|
+
|
|
8
|
+
enum PhoneType {
|
|
9
|
+
MOBILE = 0;
|
|
10
|
+
HOME = 1;
|
|
11
|
+
WORK = 2;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
message PhoneNumber {
|
|
15
|
+
required string number = 1;
|
|
16
|
+
optional PhoneType type = 2 [default = HOME];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
repeated PhoneNumber phone = 4;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
message AddressBook {
|
|
23
|
+
repeated Person person = 1;
|
|
24
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'addressbook.pb'
|
|
4
|
+
|
|
5
|
+
def list_people(address_book)
|
|
6
|
+
address_book.person.each do |person|
|
|
7
|
+
puts "Person ID: #{person.id}"
|
|
8
|
+
puts " Name: #{person.name}"
|
|
9
|
+
puts " E-mail: #{person.email}" unless person.email.empty?
|
|
10
|
+
person.phone.each do |phone_number|
|
|
11
|
+
print(case phone_number.type
|
|
12
|
+
when Tutorial::Person::PhoneType::MOBILE
|
|
13
|
+
' Mobile phone #: '
|
|
14
|
+
when Tutorial::Person::PhoneType::HOME
|
|
15
|
+
' Home phone #: '
|
|
16
|
+
when Tutorial::Person::PhoneType::WORK
|
|
17
|
+
' Work phone #: '
|
|
18
|
+
end)
|
|
19
|
+
puts phone_number.number
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
unless ARGV.size == 1
|
|
25
|
+
puts "Usage: #{$0} ADDRESS_BOOK_FILE"
|
|
26
|
+
exit
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
address_book = Tutorial::AddressBook.new
|
|
30
|
+
address_book.parse_from_file ARGV[0]
|
|
31
|
+
|
|
32
|
+
list_people address_book
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'addressbook.pb'
|
|
4
|
+
|
|
5
|
+
def prompt_for_address(person)
|
|
6
|
+
print 'Enter person ID number: '
|
|
7
|
+
person.id = STDIN.gets.strip.to_i
|
|
8
|
+
print 'Enter name: '
|
|
9
|
+
person.name = STDIN.gets.strip
|
|
10
|
+
print 'Enter email address (blank for none): '
|
|
11
|
+
email = STDIN.gets.strip
|
|
12
|
+
person.email = email unless email.empty?
|
|
13
|
+
|
|
14
|
+
loop do
|
|
15
|
+
print 'Enter a phone number (or leave blank to finish): '
|
|
16
|
+
break if (number = STDIN.gets.strip).empty?
|
|
17
|
+
|
|
18
|
+
person.phone << Tutorial::Person::PhoneNumber.new
|
|
19
|
+
person.phone.last.number = number
|
|
20
|
+
|
|
21
|
+
print 'Is this a mobile, home, or work phone? '
|
|
22
|
+
person.phone.last.type =
|
|
23
|
+
case type = STDIN.gets.strip
|
|
24
|
+
when 'mobile'
|
|
25
|
+
Tutorial::Person::PhoneType::MOBILE
|
|
26
|
+
when 'home'
|
|
27
|
+
Tutorial::Person::PhoneType::HOME
|
|
28
|
+
when 'work'
|
|
29
|
+
Tutorial::Person::PhoneType::WORK
|
|
30
|
+
else
|
|
31
|
+
puts 'Unknown phone type; leaving as default value.'
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
unless ARGV.size == 1
|
|
38
|
+
puts "Usage: #{$0} ADDRESS_BOOK_FILE"
|
|
39
|
+
exit
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
address_book = Tutorial::AddressBook.new
|
|
43
|
+
address_book.parse_from_file ARGV[0] if File.exist? ARGV[0]
|
|
44
|
+
address_book.person << Tutorial::Person.new
|
|
45
|
+
prompt_for_address address_book.person.last
|
|
46
|
+
address_book.serialize_to_file ARGV[0]
|
data/lib/protobuf.rb
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
|
|
3
|
+
module Protobuf
|
|
4
|
+
class Logger < ::Logger
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
attr_accessor :file, :level
|
|
8
|
+
|
|
9
|
+
# One-line file/level configuration
|
|
10
|
+
def configure options
|
|
11
|
+
self.file = options[:file] if options[:file]
|
|
12
|
+
self.level = options[:level] if options[:level]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def configured?
|
|
16
|
+
! instance.nil?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Use to reset the instance
|
|
20
|
+
def reset_device!
|
|
21
|
+
self.file = self.level = @__instance = nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Singleton instance
|
|
25
|
+
def instance
|
|
26
|
+
@__instance ||= begin
|
|
27
|
+
log = nil
|
|
28
|
+
if @file and @level
|
|
29
|
+
log = new(self.file)
|
|
30
|
+
log.level = self.level
|
|
31
|
+
end
|
|
32
|
+
log
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Stub out the log methods for Protobuf::Logger as singleton methods
|
|
37
|
+
[:debug, :info, :warn, :error, :fatal, :any, :add, :log].each do |m|
|
|
38
|
+
define_method(m) do |*params, &block|
|
|
39
|
+
instance && instance.__send__(m, *params, &block)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
#
|
|
45
|
+
# LogMethods module for log method including, e.g.:
|
|
46
|
+
#
|
|
47
|
+
# class MyClass
|
|
48
|
+
# include Protobuf::Logger::LogMethods
|
|
49
|
+
# ...
|
|
50
|
+
# end
|
|
51
|
+
#
|
|
52
|
+
# Produce a module to allow "include" in other classes to avoid
|
|
53
|
+
# cluttering the namespace of the including class with the other methods defined above
|
|
54
|
+
#
|
|
55
|
+
module LogMethods
|
|
56
|
+
[:debug, :info, :warn, :error, :fatal, :any, :add, :log].each do |m|
|
|
57
|
+
define_method("log_#{m}") do |*params, &block|
|
|
58
|
+
Protobuf::Logger.__send__(m, *params, &block)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Protobuf
|
|
2
|
+
module Util
|
|
3
|
+
module_function
|
|
4
|
+
|
|
5
|
+
# Takes a string or symbol and camelizes it:
|
|
6
|
+
# Expects: some_long_name
|
|
7
|
+
# Returns: SomeLongName
|
|
8
|
+
def camelize(str)
|
|
9
|
+
if (str.is_a? Array)
|
|
10
|
+
str.map{|p| camelize(p.to_s) }.join('::')
|
|
11
|
+
else
|
|
12
|
+
str.to_s.gsub(/(?:\A|_)(\w)/) { $1.upcase }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Expects: SomeLongName
|
|
17
|
+
# Returns: some_long_name
|
|
18
|
+
def underscore(str)
|
|
19
|
+
str.to_s.gsub(/\B[A-Z]/, '_\&').downcase
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Expects: SomeModule::Path
|
|
23
|
+
# Returns: some_module/path
|
|
24
|
+
def module_to_path(str)
|
|
25
|
+
pkg = str.to_s.split('::')
|
|
26
|
+
pkg.map{|e| underscore(e) }.join('/')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Expects: PackageA.PackageB
|
|
30
|
+
# Returns: package_a/package_b
|
|
31
|
+
def package_to_path(str)
|
|
32
|
+
str.to_s.split('.').map{|e| underscore(e) }.join('/')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Takes a class constant and converts it to a string resembling a java package path
|
|
36
|
+
# Expects: ModA::ModB::MyService
|
|
37
|
+
# Returns: mod_a.mod_b.MyService
|
|
38
|
+
def packagize(klass)
|
|
39
|
+
klass = klass.to_s.split('::') unless klass.is_a? Array
|
|
40
|
+
klass_name = klass.pop
|
|
41
|
+
klass.map{|e| underscore(e) }.join('.') + ".#{klass_name}"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# The reverse of packagize. Takes a string resembling a java package path
|
|
45
|
+
# and converts it into a module constant
|
|
46
|
+
# Expects: mod_a.mod_b.MyService
|
|
47
|
+
# Returns: ModA::ModB::MyService
|
|
48
|
+
def moduleize(str)
|
|
49
|
+
str = str.join('.') if str.is_a? Array
|
|
50
|
+
str.split('.').map{|e| camelize(e) }.join('::')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def constantize(klass)
|
|
54
|
+
constants = moduleize(klass).split('::')
|
|
55
|
+
constants.inject(Module.const_get(constants.shift)) {|const, obj| const.const_get(obj) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'protobuf/compiler/proto_parser'
|
|
3
|
+
require 'protobuf/compiler/nodes'
|
|
4
|
+
require 'protobuf/compiler/visitors'
|
|
5
|
+
|
|
6
|
+
module Protobuf
|
|
7
|
+
class Compiler
|
|
8
|
+
def self.compile(proto_file, proto_dir='.', out_dir='.', file_create=true)
|
|
9
|
+
self.new.compile(proto_file, proto_dir, out_dir, file_create)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def compile(proto_file, proto_dir='.', out_dir='.', file_create=true)
|
|
13
|
+
create_message(proto_file, proto_dir, out_dir, file_create)
|
|
14
|
+
create_rpc(proto_file, proto_dir, out_dir, file_create)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def create_message(proto_file, proto_dir='.', out_dir='.', file_create=true)
|
|
18
|
+
rb_file = File.join(out_dir, File.basename(proto_file).sub(/\.[^\0]*\z/, '') + '.pb.rb')
|
|
19
|
+
proto_path = validate_existence(proto_file, proto_dir)
|
|
20
|
+
|
|
21
|
+
message_visitor = Visitor::CreateMessageVisitor.new(proto_file, proto_dir, out_dir)
|
|
22
|
+
File.open(proto_path) do |file|
|
|
23
|
+
message_visitor.visit(ProtoParser.new.parse(file))
|
|
24
|
+
end
|
|
25
|
+
message_visitor.create_files(rb_file, out_dir, file_create)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def create_rpc(proto_file, proto_dir='.', out_dir='.', file_create=true)
|
|
29
|
+
message_file = File.join(out_dir, File.basename(proto_file).sub(/\.[^\0]*\z/, '') + '.pb.rb')
|
|
30
|
+
proto_path = validate_existence(proto_file, proto_dir)
|
|
31
|
+
|
|
32
|
+
rpc_visitor = Visitor::CreateRpcVisitor.new
|
|
33
|
+
File.open(proto_path) do |file|
|
|
34
|
+
rpc_visitor.visit(ProtoParser.new.parse(file))
|
|
35
|
+
end
|
|
36
|
+
rpc_visitor.create_files(message_file, out_dir, file_create)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def validate_existence(path, base_dir)
|
|
40
|
+
if File.exist?(path)
|
|
41
|
+
path
|
|
42
|
+
else
|
|
43
|
+
newpath = File.join(base_dir, path)
|
|
44
|
+
if File.exist?(newpath)
|
|
45
|
+
newpath
|
|
46
|
+
else
|
|
47
|
+
raise ArgumentError, "File does not exist: #{path}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
require 'protobuf/common/util'
|
|
2
|
+
require 'protobuf/descriptor/descriptor_proto'
|
|
3
|
+
|
|
4
|
+
module Protobuf
|
|
5
|
+
module Node
|
|
6
|
+
class Base
|
|
7
|
+
def define_in_the_file(visitor)
|
|
8
|
+
visitor.write("defined_in __FILE__") if visitor.attach_proto?
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def accept_message_visitor(visitor)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def accept_rpc_visitor(vistor)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def accept_descriptor_visitor(visitor)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class ProtoNode < Base
|
|
22
|
+
attr_reader :children
|
|
23
|
+
|
|
24
|
+
def initialize(children)
|
|
25
|
+
@children = children || []
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def accept_message_visitor(visitor)
|
|
29
|
+
visitor.write('### Generated by rprotoc. DO NOT EDIT!')
|
|
30
|
+
visitor.write("### <proto file: #{visitor.proto_file}>") if visitor.attach_proto?
|
|
31
|
+
visitor.write(visitor.commented_proto_contents) if visitor.attach_proto?
|
|
32
|
+
visitor.write(<<-EOS)
|
|
33
|
+
require 'protobuf/message/message'
|
|
34
|
+
require 'protobuf/message/enum'
|
|
35
|
+
require 'protobuf/message/extend'
|
|
36
|
+
EOS
|
|
37
|
+
@children.each {|child| child.accept_message_visitor(visitor) }
|
|
38
|
+
visitor.close_ruby
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def accept_rpc_visitor(visitor)
|
|
42
|
+
@children.each {|child| child.accept_rpc_visitor(visitor) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def accept_descriptor_visitor(visitor)
|
|
46
|
+
descriptor = Google::Protobuf::FileDescriptorProto.new(:name => visitor.filename)
|
|
47
|
+
visitor.file_descriptor = descriptor
|
|
48
|
+
visitor.in_context(descriptor) do
|
|
49
|
+
@children.each {|child| child.accept_descriptor_visitor(visitor) }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class ImportNode < Base
|
|
55
|
+
def initialize(path)
|
|
56
|
+
@path = path
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def accept_message_visitor(visitor)
|
|
60
|
+
visitor.write("require '#{visitor.required_message_from_proto(@path)}'")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def accept_descriptor_visitor(visitor)
|
|
64
|
+
visitor.current_descriptor.dependency << @path
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class PackageNode < Base
|
|
69
|
+
def initialize(path_list)
|
|
70
|
+
@path_list = path_list
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def accept_message_visitor(visitor)
|
|
74
|
+
visitor.package = @path_list.dup
|
|
75
|
+
@path_list.each do |path|
|
|
76
|
+
visitor.write("module #{Util.camelize(path)}")
|
|
77
|
+
visitor.increment
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def accept_rpc_visitor(visitor)
|
|
82
|
+
visitor.package = @path_list.dup
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def accept_descriptor_visitor(visitor)
|
|
86
|
+
visitor.current_descriptor.package = @path_list.join('.')
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class OptionNode < Base
|
|
91
|
+
def initialize(name_list, value)
|
|
92
|
+
@name_list, @value = name_list, value
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def accept_message_visitor(visitor)
|
|
96
|
+
visitor.write("::Protobuf::OPTIONS[:#{@name_list.join('.').inspect}] = #{@value.inspect}")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def accept_descriptor_visitor(visitor)
|
|
100
|
+
visitor.add_option(@name_list.join('.'), @value)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
class MessageNode < Base
|
|
105
|
+
def initialize(name, children)
|
|
106
|
+
@name, @children = name, children
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def accept_message_visitor(visitor)
|
|
110
|
+
class_name = @name.to_s
|
|
111
|
+
class_name.gsub!(/\A[a-z]/) {|c| c.upcase}
|
|
112
|
+
visitor.write("class #{class_name} < ::Protobuf::Message")
|
|
113
|
+
visitor.in_context(self.class) do
|
|
114
|
+
define_in_the_file(visitor)
|
|
115
|
+
@children.each {|child| child.accept_message_visitor(visitor) }
|
|
116
|
+
end
|
|
117
|
+
visitor.write('end')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def accept_descriptor_visitor(visitor)
|
|
121
|
+
descriptor = Google::Protobuf::DescriptorProto.new(:name => @name.to_s)
|
|
122
|
+
visitor.descriptor = descriptor
|
|
123
|
+
visitor.in_context(descriptor) do
|
|
124
|
+
@children.each {|child| child.accept_descriptor_visitor(visitor) }
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
class ExtendNode < Base
|
|
130
|
+
def initialize(name, children)
|
|
131
|
+
@name, @children = name, children
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def accept_message_visitor(visitor)
|
|
135
|
+
name = @name.is_a?(Array) ? @name.join : name.to_s
|
|
136
|
+
visitor.write("class #{name} < ::Protobuf::Message")
|
|
137
|
+
visitor.in_context(self.class) do
|
|
138
|
+
define_in_the_file(visitor)
|
|
139
|
+
@children.each {|child| child.accept_message_visitor(visitor) }
|
|
140
|
+
end
|
|
141
|
+
visitor.write('end')
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def accept_descriptor_visitor(visitor)
|
|
145
|
+
# TODO: how should i handle this?
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
class EnumNode < Base
|
|
150
|
+
def initialize(name, children)
|
|
151
|
+
@name, @children = name, children
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def accept_message_visitor(visitor)
|
|
155
|
+
visitor.write("class #{@name} < ::Protobuf::Enum")
|
|
156
|
+
visitor.in_context(self.class) do
|
|
157
|
+
define_in_the_file(visitor)
|
|
158
|
+
@children.each {|child| child.accept_message_visitor(visitor) }
|
|
159
|
+
end
|
|
160
|
+
visitor.write('end')
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def accept_descriptor_visitor(visitor)
|
|
164
|
+
descriptor = Google::Protobuf::EnumDescriptorProto.new(:name => @name.to_s)
|
|
165
|
+
visitor.enum_descriptor = descriptor
|
|
166
|
+
visitor.in_context(descriptor) do
|
|
167
|
+
@children.each {|child| child.accept_descriptor_visitor(visitor) }
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
class EnumFieldNode < Base
|
|
173
|
+
def initialize(name, value)
|
|
174
|
+
@name, @value = name, value
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def accept_message_visitor(visitor)
|
|
178
|
+
visitor.write("define :#{@name}, #{@value}")
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def accept_descriptor_visitor(visitor)
|
|
182
|
+
descriptor = Google::Protobuf::EnumValueDescriptorProto.new(:name => @name.to_s, :number => @value)
|
|
183
|
+
visitor.enum_value_descriptor = descriptor
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
class ServiceNode < Base
|
|
188
|
+
def initialize(name, children)
|
|
189
|
+
@name, @children = name, children
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def accept_message_visitor(visitor)
|
|
193
|
+
# do nothing
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def accept_rpc_visitor(visitor)
|
|
197
|
+
visitor.current_service = @name
|
|
198
|
+
@children.each {|child| child.accept_rpc_visitor(visitor) }
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def accept_descriptor_visitor(visitor)
|
|
202
|
+
descriptor = Google::Protobuf::ServiceDescriptorProto.new(:name => @name.to_s)
|
|
203
|
+
visitor.service_descriptor = descriptor
|
|
204
|
+
visitor.in_context(descriptor) do
|
|
205
|
+
@children.each {|child| child.accept_descriptor_visitor(visitor) }
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
class RpcNode < Base
|
|
211
|
+
def initialize(name, request, response)
|
|
212
|
+
@name, @request, @response = name, request, response
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def accept_message_visitor(visitor)
|
|
216
|
+
# do nothing
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def accept_rpc_visitor(visitor)
|
|
220
|
+
visitor.add_rpc(@name, @request, @response)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def accept_descriptor_visitor(visitor)
|
|
224
|
+
descriptor = Google::Protobuf::MethodDescriptorProto.new(:name => @name.to_s, :input_type => @request.to_s, :output_type => @response.to_s)
|
|
225
|
+
visitor.method_descriptor = descriptor
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
class GroupNode < Base
|
|
230
|
+
def initialize(label, name, value, children)
|
|
231
|
+
@label, @name, @value, @children = label, name, value, children
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def accept_message_visitor(visitor)
|
|
235
|
+
raise NotImplementedError
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def accept_descriptor_visitor(visitor)
|
|
239
|
+
raise NotImplementedError
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
class FieldNode < Base
|
|
244
|
+
def initialize(label, type, name, value, opts={})
|
|
245
|
+
@label, @type, @name, @value, @opts = label, type, name, value, opts
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def accept_message_visitor(visitor)
|
|
249
|
+
opts = @opts.empty? ? '' : ", #{@opts.map{|k, v| ":#{k} => #{v.inspect}" }.join(', ')}"
|
|
250
|
+
if visitor.context.first == ExtendNode
|
|
251
|
+
opts << ', :extension => true'
|
|
252
|
+
end
|
|
253
|
+
type = if @type.is_a?(Array)
|
|
254
|
+
then (@type.size > 1) ? "'#{@type.map{|e| Util.camelize(e) }.join('::')}'" : @type[0]
|
|
255
|
+
else @type
|
|
256
|
+
end
|
|
257
|
+
visitor.write("#{@label} :#{type}, :#{@name}, #{@value}#{opts}")
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def accept_descriptor_visitor(visitor)
|
|
261
|
+
descriptor = Google::Protobuf::FieldDescriptorProto.new(:name => @name.to_s, :number => @value)
|
|
262
|
+
descriptor.label = Google::Protobuf::FieldDescriptorProto::Label.const_get("LABEL_#{@label.to_s.upcase}")
|
|
263
|
+
descriptor.type = Google::Protobuf::FieldDescriptorProto::Type.const_get("TYPE_#{@type.to_s.upcase}") if predefined_type?
|
|
264
|
+
descriptor.type_name = @type.is_a?(Array) ? @type.join : @type.to_s
|
|
265
|
+
@opts.each do |key, val|
|
|
266
|
+
case key.to_sym
|
|
267
|
+
when :default
|
|
268
|
+
descriptor.default_value = val.to_s
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
visitor.field_descriptor = descriptor
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
private
|
|
275
|
+
|
|
276
|
+
def predefined_type?
|
|
277
|
+
# TODO: constantize
|
|
278
|
+
%w{double float int64 uint64 int32 fixed64 fixed32 bool string group message bytes uint32 enum sfixed32 sfixed64 sint32 sint64}.include?(@type.to_s)
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
class ExtensionsNode < Base
|
|
283
|
+
def initialize(range)
|
|
284
|
+
@range = range
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def accept_message_visitor(visitor)
|
|
288
|
+
visitor.write("extensions #{@range.first.to_s}")
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def accept_descriptor_visitor(visitor)
|
|
292
|
+
descriptor = Google::Protobuf::DescriptorProto::ExtensionRange.new(:start => @range.first.low)
|
|
293
|
+
case @range.first.high
|
|
294
|
+
when NilClass then # ignore
|
|
295
|
+
when :max then descriptor.end = 1
|
|
296
|
+
else descriptor.end = @range.first.high
|
|
297
|
+
end
|
|
298
|
+
visitor.extension_range_descriptor = descriptor
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
class ExtensionRangeNode < Base
|
|
303
|
+
attr_reader :low, :high
|
|
304
|
+
|
|
305
|
+
def initialize(low, high=nil)
|
|
306
|
+
@low, @high = low, high
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
#def accept_message_visitor(visitor)
|
|
310
|
+
#end
|
|
311
|
+
|
|
312
|
+
def to_s
|
|
313
|
+
if @high.nil?
|
|
314
|
+
@low.to_s
|
|
315
|
+
elsif @high == :max
|
|
316
|
+
"#{@low}..::Protobuf::Extend::MAX"
|
|
317
|
+
else
|
|
318
|
+
"#{@low}..#{@high}"
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|