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.
Files changed (113) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +28 -0
  4. data/README.md +216 -0
  5. data/Rakefile +1 -0
  6. data/bin/rpc_server +117 -0
  7. data/bin/rprotoc +46 -0
  8. data/examples/addressbook.pb.rb +55 -0
  9. data/examples/addressbook.proto +24 -0
  10. data/examples/reading_a_message.rb +32 -0
  11. data/examples/writing_a_message.rb +46 -0
  12. data/lib/protobuf.rb +6 -0
  13. data/lib/protobuf/common/exceptions.rb +11 -0
  14. data/lib/protobuf/common/logger.rb +64 -0
  15. data/lib/protobuf/common/util.rb +59 -0
  16. data/lib/protobuf/common/wire_type.rb +10 -0
  17. data/lib/protobuf/compiler/compiler.rb +52 -0
  18. data/lib/protobuf/compiler/nodes.rb +323 -0
  19. data/lib/protobuf/compiler/proto.y +216 -0
  20. data/lib/protobuf/compiler/proto2.ebnf +79 -0
  21. data/lib/protobuf/compiler/proto_parser.rb +1425 -0
  22. data/lib/protobuf/compiler/template/rpc_bin.erb +4 -0
  23. data/lib/protobuf/compiler/template/rpc_client.erb +18 -0
  24. data/lib/protobuf/compiler/template/rpc_service.erb +25 -0
  25. data/lib/protobuf/compiler/template/rpc_service_implementation.erb +42 -0
  26. data/lib/protobuf/compiler/visitors.rb +302 -0
  27. data/lib/protobuf/descriptor/descriptor.proto +286 -0
  28. data/lib/protobuf/descriptor/descriptor.rb +55 -0
  29. data/lib/protobuf/descriptor/descriptor_builder.rb +143 -0
  30. data/lib/protobuf/descriptor/descriptor_proto.rb +138 -0
  31. data/lib/protobuf/descriptor/enum_descriptor.rb +33 -0
  32. data/lib/protobuf/descriptor/field_descriptor.rb +49 -0
  33. data/lib/protobuf/descriptor/file_descriptor.rb +37 -0
  34. data/lib/protobuf/message/decoder.rb +83 -0
  35. data/lib/protobuf/message/encoder.rb +46 -0
  36. data/lib/protobuf/message/enum.rb +62 -0
  37. data/lib/protobuf/message/extend.rb +8 -0
  38. data/lib/protobuf/message/field.rb +701 -0
  39. data/lib/protobuf/message/message.rb +402 -0
  40. data/lib/protobuf/message/protoable.rb +38 -0
  41. data/lib/protobuf/rpc/buffer.rb +74 -0
  42. data/lib/protobuf/rpc/client.rb +268 -0
  43. data/lib/protobuf/rpc/client_connection.rb +225 -0
  44. data/lib/protobuf/rpc/error.rb +34 -0
  45. data/lib/protobuf/rpc/error/client_error.rb +31 -0
  46. data/lib/protobuf/rpc/error/server_error.rb +43 -0
  47. data/lib/protobuf/rpc/rpc.pb.rb +107 -0
  48. data/lib/protobuf/rpc/server.rb +183 -0
  49. data/lib/protobuf/rpc/service.rb +244 -0
  50. data/lib/protobuf/rpc/stat.rb +70 -0
  51. data/lib/protobuf/version.rb +3 -0
  52. data/proto/rpc.proto +73 -0
  53. data/protobuf.gemspec +25 -0
  54. data/script/mk_parser +2 -0
  55. data/spec/functional/embedded_service_spec.rb +7 -0
  56. data/spec/proto/test.pb.rb +31 -0
  57. data/spec/proto/test.proto +31 -0
  58. data/spec/proto/test_service.rb +30 -0
  59. data/spec/proto/test_service_impl.rb +17 -0
  60. data/spec/spec_helper.rb +26 -0
  61. data/spec/unit/client_spec.rb +128 -0
  62. data/spec/unit/common/logger_spec.rb +121 -0
  63. data/spec/unit/enum_spec.rb +13 -0
  64. data/spec/unit/message_spec.rb +67 -0
  65. data/spec/unit/server_spec.rb +27 -0
  66. data/spec/unit/service_spec.rb +75 -0
  67. data/test/check_unbuild.rb +30 -0
  68. data/test/data/data.bin +3 -0
  69. data/test/data/data_source.py +14 -0
  70. data/test/data/types.bin +0 -0
  71. data/test/data/types_source.py +22 -0
  72. data/test/data/unk.png +0 -0
  73. data/test/proto/addressbook.pb.rb +66 -0
  74. data/test/proto/addressbook.proto +33 -0
  75. data/test/proto/addressbook_base.pb.rb +58 -0
  76. data/test/proto/addressbook_base.proto +26 -0
  77. data/test/proto/addressbook_ext.pb.rb +20 -0
  78. data/test/proto/addressbook_ext.proto +6 -0
  79. data/test/proto/collision.pb.rb +17 -0
  80. data/test/proto/collision.proto +5 -0
  81. data/test/proto/ext_collision.pb.rb +24 -0
  82. data/test/proto/ext_collision.proto +8 -0
  83. data/test/proto/ext_range.pb.rb +22 -0
  84. data/test/proto/ext_range.proto +7 -0
  85. data/test/proto/float_default.proto +10 -0
  86. data/test/proto/lowercase.pb.rb +30 -0
  87. data/test/proto/lowercase.proto +9 -0
  88. data/test/proto/merge.pb.rb +39 -0
  89. data/test/proto/merge.proto +15 -0
  90. data/test/proto/nested.pb.rb +30 -0
  91. data/test/proto/nested.proto +9 -0
  92. data/test/proto/optional_field.pb.rb +35 -0
  93. data/test/proto/optional_field.proto +12 -0
  94. data/test/proto/packed.pb.rb +22 -0
  95. data/test/proto/packed.proto +6 -0
  96. data/test/proto/rpc.proto +6 -0
  97. data/test/proto/types.pb.rb +84 -0
  98. data/test/proto/types.proto +37 -0
  99. data/test/test_addressbook.rb +56 -0
  100. data/test/test_compiler.rb +325 -0
  101. data/test/test_descriptor.rb +122 -0
  102. data/test/test_enum_value.rb +41 -0
  103. data/test/test_extension.rb +36 -0
  104. data/test/test_lowercase.rb +11 -0
  105. data/test/test_message.rb +128 -0
  106. data/test/test_optional_field.rb +103 -0
  107. data/test/test_packed_field.rb +40 -0
  108. data/test/test_parse.rb +15 -0
  109. data/test/test_repeated_types.rb +132 -0
  110. data/test/test_serialize.rb +61 -0
  111. data/test/test_standard_message.rb +96 -0
  112. data/test/test_types.rb +226 -0
  113. 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
@@ -0,0 +1,3 @@
1
+
2
+ John Doe� jdoe@example.com"
3
+ 555-4321
@@ -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()
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