protobuf 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,121 @@
|
|
1
|
+
require 'protobuf/common/logger'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
describe Protobuf::Logger do
|
5
|
+
|
6
|
+
subject { Protobuf::Logger }
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
Protobuf::Logger.reset_device!
|
10
|
+
Protobuf::Logger.file = '/dev/null'
|
11
|
+
Protobuf::Logger.level = ::Logger::INFO
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.instance' do
|
15
|
+
|
16
|
+
it 'doesn\'t create a logger if the file was not set' do
|
17
|
+
subject.file = nil
|
18
|
+
subject.instance.should be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'doesn\'t create a logger if the level was not set' do
|
22
|
+
subject.level = nil
|
23
|
+
subject.instance.should be_nil
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'gets a new instance of the logger when file and level are set' do
|
27
|
+
subject.file.should_not be_nil
|
28
|
+
subject.level.should_not be_nil
|
29
|
+
subject.instance.should_not be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'keeps the same object from multiple calls to instance' do
|
33
|
+
subject.instance === subject.instance
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '.configure' do
|
39
|
+
before(:each) { subject.reset_device! }
|
40
|
+
it 'sets the file and level in one call' do
|
41
|
+
subject.file.should_not be
|
42
|
+
subject.level.should_not be
|
43
|
+
subject.instance.should_not be
|
44
|
+
subject.configure :file => 'myfile.log', :level => ::Logger::WARN
|
45
|
+
subject.file.should == 'myfile.log'
|
46
|
+
subject.level.should == ::Logger::WARN
|
47
|
+
subject.instance.level.should == ::Logger::WARN
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '.reset_device!' do
|
53
|
+
|
54
|
+
it 'resets the logger instance, file, and level' do
|
55
|
+
subject.instance.should be
|
56
|
+
subject.file.should be
|
57
|
+
subject.level.should be
|
58
|
+
subject.reset_device!
|
59
|
+
subject.instance.should_not be
|
60
|
+
subject.file.should_not be
|
61
|
+
subject.level.should_not be
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when logging' do
|
67
|
+
|
68
|
+
it 'doesn\'t raise errors when log instance is nil' do
|
69
|
+
subject.reset_device!
|
70
|
+
subject.instance.should be_nil
|
71
|
+
expect {
|
72
|
+
subject.debug 'No errors here'
|
73
|
+
subject.info 'No errors here'
|
74
|
+
subject.warn 'No errors here'
|
75
|
+
subject.error 'No errors here'
|
76
|
+
subject.fatal 'No errors here'
|
77
|
+
subject.add 'No errors here'
|
78
|
+
subject.log 'No errors here'
|
79
|
+
}.should_not raise_error
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'logs correctly when instance is valid' do
|
83
|
+
subject.instance.should_not be_nil
|
84
|
+
subject.instance.should_receive(:info).with('Should log great')
|
85
|
+
subject.info 'Should log great'
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
describe Protobuf::Logger::LogMethods do
|
91
|
+
|
92
|
+
context 'when included in another class' do
|
93
|
+
|
94
|
+
before(:all) do
|
95
|
+
class MyTestClass
|
96
|
+
include Protobuf::Logger::LogMethods
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
subject { MyTestClass.new }
|
101
|
+
|
102
|
+
it 'responds to all logger methods' do
|
103
|
+
subject.should respond_to :log_debug
|
104
|
+
subject.should respond_to :log_info
|
105
|
+
subject.should respond_to :log_warn
|
106
|
+
subject.should respond_to :log_error
|
107
|
+
subject.should respond_to :log_fatal
|
108
|
+
subject.should respond_to :log_add
|
109
|
+
subject.should respond_to :log_log
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'passes all embedded log calls to Logger instance' do
|
113
|
+
Protobuf::Logger.instance.should_receive(:debug).with('log this')
|
114
|
+
subject.log_debug('log this')
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spec/proto/test.pb'
|
3
|
+
|
4
|
+
describe Protobuf::Enum do
|
5
|
+
context 'when coercing from enum' do
|
6
|
+
subject { Spec::Proto::StatusType::PENDING }
|
7
|
+
it { should == 0 }
|
8
|
+
end
|
9
|
+
context 'when coercing from integer' do
|
10
|
+
subject { 0 }
|
11
|
+
it { should == Spec::Proto::StatusType::PENDING }
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spec/proto/test.pb'
|
3
|
+
|
4
|
+
describe Protobuf::Message do
|
5
|
+
|
6
|
+
context 'when converting to json' do
|
7
|
+
|
8
|
+
it "should be jsonable" do
|
9
|
+
msg = Spec::Proto::ResourceFindRequest.new
|
10
|
+
msg.should respond_to(:to_json)
|
11
|
+
msg.name = 'Jeff'
|
12
|
+
msg.active = false
|
13
|
+
msg.to_json.should == '{"name":"Jeff","active":false}'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should generate nested messages into nested json objects' do
|
17
|
+
date_created = Time.now.to_i
|
18
|
+
|
19
|
+
nested = Spec::Proto::Nested.new
|
20
|
+
nested.name = 'NESTED'
|
21
|
+
nested.resource = Spec::Proto::Resource.new.tap do |r|
|
22
|
+
r.name = 'RESOURCE SINGLE'
|
23
|
+
r.date_created = date_created
|
24
|
+
r.status = Spec::Proto::StatusType::PENDING
|
25
|
+
end
|
26
|
+
2.times do |i|
|
27
|
+
nested.multiple_resources << Spec::Proto::Resource.new.tap do |r|
|
28
|
+
r.name = 'RESOURCE MULTIPLE %d' % i
|
29
|
+
r.date_created = date_created
|
30
|
+
r.status = Spec::Proto::StatusType::PENDING
|
31
|
+
end
|
32
|
+
end
|
33
|
+
nested.status = Spec::Proto::StatusType::ENABLED
|
34
|
+
|
35
|
+
nested.to_json.should == %Q{{"name":"NESTED","resource":{"name":"RESOURCE SINGLE","date_created":#{date_created},"status":0,"repeated_enum":[]},"multiple_resources":[{"name":"RESOURCE MULTIPLE 0","date_created":#{date_created},"status":0,"repeated_enum":[]},{"name":"RESOURCE MULTIPLE 1","date_created":#{date_created},"status":0,"repeated_enum":[]}],"status":1}}
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when converting to a hash' do
|
42
|
+
|
43
|
+
context 'when message has repeated enum field' do
|
44
|
+
|
45
|
+
it 'provides an array of integers' do
|
46
|
+
resource = Spec::Proto::Resource.new :repeated_enum => [
|
47
|
+
Spec::Proto::StatusType::PENDING,
|
48
|
+
Spec::Proto::StatusType::ENABLED,
|
49
|
+
Spec::Proto::StatusType::ENABLED,
|
50
|
+
Spec::Proto::StatusType::DISABLED,
|
51
|
+
Spec::Proto::StatusType::DELETED
|
52
|
+
]
|
53
|
+
|
54
|
+
resource.to_hash[:repeated_enum].should == [
|
55
|
+
Spec::Proto::StatusType::PENDING.value,
|
56
|
+
Spec::Proto::StatusType::ENABLED.value,
|
57
|
+
Spec::Proto::StatusType::ENABLED.value,
|
58
|
+
Spec::Proto::StatusType::DISABLED.value,
|
59
|
+
Spec::Proto::StatusType::DELETED.value
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'protobuf/rpc/server'
|
3
|
+
require 'spec/proto/test_service_impl'
|
4
|
+
|
5
|
+
describe Protobuf::Rpc::Server do
|
6
|
+
context 'when sending response objects' do
|
7
|
+
it 'should be able to send a hash object as a response' do
|
8
|
+
server = Protobuf::Rpc::Server.new
|
9
|
+
|
10
|
+
# Setup the right mocks
|
11
|
+
server.instance_variable_set(:@klass, Spec::Proto::TestService)
|
12
|
+
response_wrapper = mock('response')
|
13
|
+
response_wrapper.stub(:response_proto=)
|
14
|
+
server.instance_variable_set(:@response, response_wrapper)
|
15
|
+
Spec::Proto::TestService.stub_chain(:rpcs, :[], :[], :response_type).and_return(Spec::Proto::ResourceFindRequest)
|
16
|
+
|
17
|
+
# Setup expectations
|
18
|
+
hash_response = {:name => 'Test Name', :active => false}
|
19
|
+
expected = Spec::Proto::ResourceFindRequest.new(hash_response)
|
20
|
+
Spec::Proto::ResourceFindRequest.should_receive(:new).with(hash_response).and_return(expected)
|
21
|
+
server.should_not_receive(:handle_error)
|
22
|
+
|
23
|
+
# Call the method
|
24
|
+
server.send(:parse_response_from_service, hash_response)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spec/proto/test_service_impl'
|
3
|
+
|
4
|
+
describe Protobuf::Rpc::Service do
|
5
|
+
|
6
|
+
context 'when configuring' do
|
7
|
+
before :each do
|
8
|
+
reset_service_location Spec::Proto::TestService
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have a default location configured' do
|
12
|
+
Spec::Proto::TestService.host.should == Protobuf::Rpc::Service::DEFAULT_LOCATION[:host]
|
13
|
+
Spec::Proto::TestService.port.should == Protobuf::Rpc::Service::DEFAULT_LOCATION[:port]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be able to pre-configure a service location for clients" do
|
17
|
+
Spec::Proto::TestService.located_at 'google.com:12345'
|
18
|
+
client = Spec::Proto::TestService.client
|
19
|
+
client.options[:host].should == 'google.com'
|
20
|
+
client.options[:port].should == 12345
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should be able to configure and read the host' do
|
24
|
+
Spec::Proto::TestService.configure :host => 'somehost.com'
|
25
|
+
Spec::Proto::TestService.host.should == 'somehost.com'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should be able to configure and read the port' do
|
29
|
+
Spec::Proto::TestService.configure :port => 12345
|
30
|
+
Spec::Proto::TestService.port.should == 12345
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should skip configuring location if the location passed does not match host:port syntax' do
|
34
|
+
invalid_locations = [nil, 'myhost:', ':9939', 'badhost123']
|
35
|
+
invalid_locations.each do |location|
|
36
|
+
Spec::Proto::TestService.located_at location
|
37
|
+
Spec::Proto::TestService.host.should == Protobuf::Rpc::Service::DEFAULT_LOCATION[:host]
|
38
|
+
Spec::Proto::TestService.port.should == Protobuf::Rpc::Service::DEFAULT_LOCATION[:port]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when server calls the service method' do
|
44
|
+
|
45
|
+
before(:all) do
|
46
|
+
class ::NewTestService < Protobuf::Rpc::Service
|
47
|
+
rpc :bad_method, Spec::Proto::ResourceFindRequest, Spec::Proto::Resource
|
48
|
+
rpc :bad_var, Spec::Proto::ResourceFindRequest, Spec::Proto::Resource
|
49
|
+
def bad_method
|
50
|
+
hash = {}
|
51
|
+
hash[:one].explode
|
52
|
+
end
|
53
|
+
def bad_var
|
54
|
+
invalidvar
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'raises an undefined method name error when calling a method on a non-existant object' do
|
60
|
+
expect {
|
61
|
+
req = mock('RequestWrapper', :request_proto => Spec::Proto::ResourceFindRequest.new.to_s)
|
62
|
+
::NewTestService.new.bad_method(req)
|
63
|
+
}.to raise_error(NoMethodError)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'raises a name error when accessing a non-existant object' do
|
67
|
+
expect {
|
68
|
+
req = mock('RequestWrapper', :request_proto => Spec::Proto::ResourceFindRequest.new.to_s)
|
69
|
+
::NewTestService.new.bad_var(req)
|
70
|
+
}.to raise_error(NameError)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
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(['age', '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/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
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import types_pb2
|
2
|
+
import sys
|
3
|
+
|
4
|
+
types = types_pb2.TestTypes()
|
5
|
+
types.type1 = 0.01
|
6
|
+
types.type2 = 0.1
|
7
|
+
types.type3 = 1
|
8
|
+
types.type4 = 10
|
9
|
+
types.type5 = 100
|
10
|
+
types.type6 = 1000
|
11
|
+
types.type7 = -1
|
12
|
+
types.type8 = -10
|
13
|
+
types.type9 = 10000
|
14
|
+
types.type10 = 100000
|
15
|
+
types.type11 = False
|
16
|
+
types.type12 = 'hello all types'
|
17
|
+
# TODO test type13
|
18
|
+
#types.type13 =
|
19
|
+
|
20
|
+
f = open('types.bin', 'wb')
|
21
|
+
f.write(types.SerializeToString())
|
22
|
+
f.close()
|
data/test/data/unk.png
ADDED
Binary file
|
@@ -0,0 +1,66 @@
|
|
1
|
+
### Generated by rprotoc. DO NOT EDIT!
|
2
|
+
### <proto file: test/proto/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
|
+
# optional uint32 age = 5 [default = 20];
|
23
|
+
#
|
24
|
+
# extensions 100 to 200;
|
25
|
+
# }
|
26
|
+
#
|
27
|
+
# /*
|
28
|
+
# extend Person {
|
29
|
+
# optional int32 age = 100;
|
30
|
+
# }
|
31
|
+
# */
|
32
|
+
#
|
33
|
+
# message AddressBook {
|
34
|
+
# repeated Person person = 1;
|
35
|
+
# }
|
36
|
+
|
37
|
+
require 'protobuf/message/message'
|
38
|
+
require 'protobuf/message/enum'
|
39
|
+
require 'protobuf/message/extend'
|
40
|
+
|
41
|
+
module Tutorial
|
42
|
+
class Person < ::Protobuf::Message
|
43
|
+
defined_in __FILE__
|
44
|
+
required :string, :name, 1
|
45
|
+
required :int32, :id, 2
|
46
|
+
optional :string, :email, 3
|
47
|
+
class PhoneType < ::Protobuf::Enum
|
48
|
+
defined_in __FILE__
|
49
|
+
define :MOBILE, 0
|
50
|
+
define :HOME, 1
|
51
|
+
define :WORK, 2
|
52
|
+
end
|
53
|
+
class PhoneNumber < ::Protobuf::Message
|
54
|
+
defined_in __FILE__
|
55
|
+
required :string, :number, 1
|
56
|
+
optional :PhoneType, :type, 2, :default => :HOME
|
57
|
+
end
|
58
|
+
repeated :PhoneNumber, :phone, 4
|
59
|
+
optional :uint32, :age, 5, :default => 20
|
60
|
+
extensions 100..200
|
61
|
+
end
|
62
|
+
class AddressBook < ::Protobuf::Message
|
63
|
+
defined_in __FILE__
|
64
|
+
repeated :Person, :person, 1
|
65
|
+
end
|
66
|
+
end
|