protobuf 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ pkg/*
3
+ .bundle
4
+ .rvmrc
5
+ *.log
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ protobuf (1.0.0)
5
+ eventmachine (~> 0.12.10)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.1.2)
11
+ eventmachine (0.12.10)
12
+ rake (0.8.7)
13
+ rspec (2.7.0)
14
+ rspec-core (~> 2.7.0)
15
+ rspec-expectations (~> 2.7.0)
16
+ rspec-mocks (~> 2.7.0)
17
+ rspec-core (2.7.1)
18
+ rspec-expectations (2.7.0)
19
+ diff-lcs (~> 1.1.2)
20
+ rspec-mocks (2.7.0)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ protobuf!
27
+ rake (~> 0.8.7)
28
+ rspec (~> 2.7.0)
data/README.md ADDED
@@ -0,0 +1,216 @@
1
+ protobuf
2
+ ========
3
+
4
+ Protobuf is an implementation of [Google's protocol buffers][google-pb] in ruby. It's a gem for managing 3 things:
5
+
6
+ 1. Compiling `.proto` definitions to ruby
7
+ 2. Provide a Socket-RPC mechanism for calling services
8
+ 3. Provide RPC interop between ruby and other protobuf-rpc aware implementations for different languages (e.g. [protobuf-socket-rpc][])
9
+
10
+ So let's dive in and see how to work with all three.
11
+
12
+ 1. Compile `.proto` definitions to ruby
13
+ =======================================
14
+
15
+ Protocol Buffers are great because they allow you to clearly define data storage or data transfer packets. Google officially supports Java, C++, and Python for compilation and usage. Let's make it ruby aware!
16
+
17
+ Let's say you have a `defs.proto` file that defines a User message.
18
+
19
+ package mycompany;
20
+ message User {
21
+ required string first_name = 1;
22
+ required string last_name = 1;
23
+ }
24
+
25
+ Now let's compile that definition to ruby:
26
+
27
+ $ rprotoc defs.proto -o ./lib
28
+
29
+ The previous line will take whatever is defined in defs.proto and output ruby classes to the `./lib` directory, obeying the package directive. Assuming that's all defs.proto had defined, `./lib` should now look like this:
30
+
31
+ - lib
32
+ |- mycompany
33
+ |- defs.pb.rb
34
+
35
+ And `defs.pb.rb` should look like this:
36
+
37
+ module Mycompany
38
+ class User
39
+ optional :string, :first_name, 1
40
+ optional :string, :last_name, 2
41
+ end
42
+ end
43
+
44
+ You can then use that class just like normal:
45
+
46
+ require 'lib/mycompany/user.pb'
47
+
48
+ # dot notation reading/writing fields
49
+ user = Mycompany::User.new
50
+ user.first_name = "Lloyd"
51
+ user.last_name = "Christmas"
52
+ user.first_name # => "Lloyd"
53
+
54
+ # or pass in the fields as a hash to the initializer
55
+ user = Mycompany::User.new :first_name => "Lloyd", :last_name => "Christmas"
56
+ user.first_name # => Lloyd
57
+ user.last_name # => Christmas
58
+
59
+ ------------------
60
+
61
+ 2. RPC
62
+ ======
63
+
64
+ RPC is one of many technologies that tries to solve the problem of getting smaller pieces of data from one place to another. Many will argue for or against RPC and its usefulness, but I'm not going to do that here. Google's Protocol Buffers relies on RPC and that's why you're here.
65
+
66
+ Any discussion about RPC leads to a discussion about clients and servers and the remote procedures themselves. For our purposes, we'll talk about a `Client` (process that is calling the server/service), a `Service` (the remote procedure), and a `Server` (the process that manages one or more services). We'll start with the Service first.
67
+
68
+ **Services**
69
+
70
+ Services are simply classes that have endpoint methods defined. Here's what one looks like in protobuf:
71
+
72
+ message UserRequest {
73
+ optional string email = 1;
74
+ }
75
+ message UserList {
76
+ repeated User users = 1;
77
+ }
78
+ service UserService {
79
+ rpc Find (UserRequest) returns (UserList);
80
+ }
81
+
82
+ And the equivalent ruby stub for the service (generated with `rprotoc`):
83
+
84
+ # lib/mycompany/user_service.rb
85
+ module Mycompany
86
+ class UserService < Protobuf::Rpc::Service
87
+ rpc :find, UserRequest, UserList
88
+ end
89
+ end
90
+
91
+ Recognize that the extra messages would actually have gone into the `defs.pb.rb` file while the service stub would receive it's own file at `user_service.rb`.
92
+
93
+ **Important Note: The *stubbed* class here is a *stub*. You should not alter it directly in any way as it will break your definition. Read on to learn how to use this stub.**
94
+
95
+ Did you read the note above? Go read it. I'll wait.
96
+
97
+ Ok, now that you have a compiled service stub, you'll want to require it from `lib` and implement the methods. You'll notice when you compile the stub there is a large comment at the top of the file. You can use this code comment to start your real implementation. Go ahead and copy it to your services directory (probably `app/services` if we're in rails).
98
+
99
+ # app/services/user_service.rb
100
+ require 'lib/mycompany/user_service'
101
+ module Mycompany
102
+ class UserService
103
+
104
+ # request -> Mycompany::UserRequest
105
+ # response -> Mycompany::UserResponse
106
+ def find
107
+ # request.email will be the unpacked string that was sent by the client request
108
+ User.find_by_email(request.email).each do |user|
109
+ # must only use a proto instance of Mycompany::User when appending to the `users` field
110
+ response.users << user.to_proto
111
+ end
112
+ end
113
+
114
+ end
115
+ end
116
+
117
+ Simply implement the instance method for the defined rpc. No other methods will be allowed in the class (even helpers or private methods). An implicit `request` and `response` object are provided for you, pre-instantiated, and in the case of the request, already are populated with the data that was sent by the client.
118
+
119
+ If you need to create your own response object (a valid case), be sure to assign it back to the instance by using `self.response = your_response_obj`. The object you assign **MUST** be of the defined return type, in this case `Mycompany::UserList`. Any other type will result in an error.
120
+
121
+ Triggering an error from the service is simple:
122
+
123
+ #...
124
+ def find
125
+ if request.email.blank?
126
+ rpc_failed 'Unable to find user without an email'
127
+ else
128
+ # query/populate response
129
+ end
130
+ end
131
+
132
+ This means that the client's `on_failure` callback will be invoked instead of the `on_success` callback. Read more below on client callbacks.
133
+
134
+ I find it very convenient to use a CRUD-style interface when defining certain data services, though this is certainly not always the case.
135
+
136
+ **Servers**
137
+
138
+ A service is nothing without being hooked up to a socket. It's the nerdy kid waiting by the telephone for someone to call without knowing that the phone company disconnected their house. Sad and pathetic. So hook the phone lines!
139
+
140
+ $ rpc_server -o myserver.com -p 9939 -e production -l ./log/protobuf.log config/environment.rb
141
+
142
+ The previous call will start an EventMachine server running on the given host and port which will load your application into memory. You certainly don't have to run rails or any other framework, just make sure you have some kind of file that will load your services all into memory. The server doesn't know where you put your code, so tell it.
143
+
144
+ Be aware that server needs to be able to translate the socket stream of bytes into an actual protobuf request object. If the definition for that request object aren't known to the server, you're going to have a long day getting this going. It's necessary to store all your definitions and their generated classes in a shared repository (read: gem) that both client and server have access to in their respective load paths.
145
+
146
+ Once the server starts, you should see it as a running process with `ps`. Sending a KILL, QUIT, or TERM signal to the pid will result in shutting the server down gracefully.
147
+
148
+ $ ps aux | grep rpc_server
149
+ 1234 ... rpc_server myservice.com:9939
150
+
151
+ $ kill -QUIT 1234
152
+ rpc_server shutdown
153
+
154
+ **Clients**
155
+
156
+ A lot of work has gone into making the client calls simple and easy to use yet still powerful. Clients have a DSL that feels very ajax-ish, mostly because of the nature of EventMachine, but I also think it works quite well.
157
+
158
+ # require the defs from the shared gem/repo
159
+ require 'sharedgem/mycompany/user.pb'
160
+ require 'sharedgem/mycompany/user_service'
161
+
162
+ # Create a request object for the method we are invoking
163
+ req = Mycompany::UserRequest.new(:email => 'jeff@gmail.com')
164
+
165
+ # Use the UserService class to generate a client, invoke the rpc method
166
+ # while passing the request object
167
+ Mycompany::UserService.client.find(req) do |c|
168
+ # This block will be executed (registering the callbacks)
169
+ # before the request actualy occurs.
170
+ # the `c` param in this block is the `.client` object
171
+ # that is generated from the call above
172
+
173
+ # Register a block for execution when the response
174
+ # is deemed successful from the service. Accepts
175
+ # the unpacked response as its only parameter
176
+ c.on_success do |response|
177
+ response.users.each do |u|
178
+ puts u.inspect
179
+ end
180
+ end
181
+
182
+ # Register a block for execution when the response
183
+ # is deemed a failure. This can be either a client-side
184
+ # or server-side failure. The object passed the to the
185
+ # block has a `message` and a `code` attribute
186
+ # to aid in logging/diagnosing the failure.
187
+ c.on_failure do |err|
188
+ puts 'It failed: ' + err.message
189
+ end
190
+ end
191
+
192
+ Many different options can be passed to the `.client` call above (such as `:async => true` or `:timeout => 600`). See the `lib/protobuf/rpc/client.rb` and `lib/protobuf/rpc/service.rb` files for more documentation. It hsould be noted that the default behavior of `UserService.client` is to return a blocking client. The nature of using Client calls within an framework like Rails demands a blocking call if the response of a web request is dependent on data returned from the service.
193
+
194
+ ---
195
+
196
+ 3. RPC Interop
197
+ ==============
198
+
199
+ The main reason I wrote this gem was to provide a ruby implementation to google's protobuf that worked on the RPC layer with a Java Service layer that was already running [protobuf-socket-rpc][], the supported socket rpc library for protobuf from Google. The [old gem][] did not provide a very robust RPC implementation and it most certainly did not work with the Java stack.
200
+
201
+ ---
202
+
203
+ Accreditation & Caveats
204
+ =======================
205
+
206
+ It must be noted a large amount of the code in this library was taken from the [ruby-protobuf][old gem] gem. Its authors and I were unable to reach a communication point to be able to merge all of my RPC updates in with their master. Unfortunately I just simply couldn't use their RPC code and so I've decided to diverge from their codeset. I take no credit whatsoever for the (de)serialization and `rprotoc` code generation original work, though I have modified it slightly to be more compliant with my understanding of the pb spec. I want to say thanks to the original devs for the good work they did to get me most of the way there. The code was initially diverged at their 0.4.0 version.
207
+
208
+ It should also be noted that there are many more features I haven't really shown here, so please let me know if you have any questions on usage or support for various features. Happy protobufing.
209
+
210
+ -- BJ Neilsen, [@localshred][], [rand9.com][]
211
+
212
+ [google-pb]: http://code.google.com/p/protobuf "Google Protocol Buffers"
213
+ [protobuf-socket-rpc]: http://code.google.com/p/protobuf-socket-rpc/ "Google's official Socket-RPC library for protobuf"
214
+ [old gem]: https://github.com/macks/ruby-protobuf "Macks ruby-protobuf on github"
215
+ [@localshred]: http://twitter.com/localshred "Follow on twitter @localshred"
216
+ [rand9.com]: http://rand9.com "Blog"
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/rpc_server ADDED
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'ostruct'
5
+ require 'logger'
6
+ require 'protobuf'
7
+ require 'protobuf/rpc/server'
8
+
9
+ [:INT, :QUIT, :TERM].each do |sig|
10
+ trap(sig) do
11
+ EventMachine.stop_event_loop if EventMachine.reactor_running?
12
+ Protobuf::Logger.info 'Shutdown complete'
13
+ $stdout.puts 'Shutdown complete'
14
+ end
15
+ end
16
+
17
+ # Default options
18
+ server = OpenStruct.new({
19
+ :app => nil,
20
+ :env => ENV['RPC_SERVER_ENV'] || 'development',
21
+ :host => '127.0.0.1',
22
+ :port => 9595,
23
+ :log => File.expand_path('./protobuf.log'),
24
+ :level => ::Logger::INFO,
25
+ :debug => false
26
+ })
27
+
28
+ parser = OptionParser.new do |opts|
29
+ opts.banner = "Usage: rpc_server [options] app_file.rb"
30
+
31
+ opts.on("-e ENVIRONMENT", "--env=ENVIRONMENT", "Environment to run the server") do |v|
32
+ server.env = ENV['RACK_ENV'] = ENV['RAILS_ENV'] = ENV['APP_ENV'] = v
33
+ end
34
+
35
+ opts.on("-o HOST", "--host=HOST", "Server host") do |v|
36
+ server.host = v
37
+ end
38
+
39
+ opts.on("-p PORT", "--port=PORT", Integer, "Server port") do |v|
40
+ server.port = v
41
+ end
42
+
43
+ opts.on("-l LOG_FILE", "--log=LOG_FILE", "Log file or device") do |v|
44
+ server.log = v
45
+ end
46
+
47
+ opts.on("-v N", "--level=N", Integer, "Log level to use, 0-5 (see http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/)") do |v|
48
+ server.level = v.to_i
49
+ end
50
+
51
+ opts.on("-d", "--[no-]debug", "Debug Mode. Override log level to DEBUG.") do |v|
52
+ server.debug = v
53
+ server.level = ::Logger::DEBUG if v === true
54
+ end
55
+
56
+ opts.separator ""
57
+ opts.separator "Common options:"
58
+
59
+ opts.on_tail("-h", "--help", "Show this message") do
60
+ puts opts
61
+ exit
62
+ end
63
+
64
+ opts.on_tail("--version", "Show version") do
65
+ puts Protobuf::VERSION
66
+ exit
67
+ end
68
+ end
69
+
70
+ begin
71
+ parser.parse!
72
+
73
+ if ARGV.empty?
74
+ raise 'You must specify an app file to use.'
75
+ else
76
+ server.app = ARGV.pop
77
+ raise 'Invalid app file specified (%s).' % server.app unless File.exists?(server.app)
78
+ end
79
+
80
+ # Configure the Protobuf::Logger
81
+ Protobuf::Logger.configure :file => server.log, :level => server.debug ? ::Logger::DEBUG : server.level
82
+
83
+ # Output the server opts
84
+ Protobuf::Logger.debug 'Debugging options:'
85
+ Protobuf::Logger.debug server.inspect
86
+
87
+ # Ensure errors thrown within EM are caught and logged appropriately
88
+ EventMachine.error_handler do |error|
89
+ if error.message == 'no acceptor'
90
+ raise 'Failed binding to %s:%d (%s)' % [server.host, server.port, error.message]
91
+ else
92
+ Protobuf::Logger.error error.message
93
+ Protobuf::Logger.error error.backtrace.join("\n")
94
+ end
95
+ end
96
+
97
+ # Set the name of the process
98
+ $0 = 'rpc_server %s:%d' % [server.host, server.port]
99
+
100
+ # Require the given application file
101
+ require server.app
102
+
103
+ # Startup and run the rpc server
104
+ EM.schedule do
105
+ EventMachine.start_server(server.host, server.port, Protobuf::Rpc::Server) && \
106
+ Protobuf::Logger.info('RPC Server listening at %s:%d in %s' % [server.host, server.port, server.env])
107
+ end
108
+
109
+ # Join or start the reactor
110
+ EM.reactor_running? ? EM.reactor_thread.join : EM.run
111
+ rescue
112
+ msg = 'ERROR: RPC Server failed to start. %s' % $!.message
113
+ $stderr.puts msg, *($!.backtrace)
114
+ Protobuf::Logger.error msg
115
+ Protobuf::Logger.error $!.backtrace.join("\n")
116
+ exit 1
117
+ end
data/bin/rprotoc ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ if File.directory?("#{File.dirname(__FILE__)}/../lib")
6
+ $: << "#{File.dirname(__FILE__)}/../lib"
7
+ else
8
+ require 'rubygems'
9
+ gem 'protobuf'
10
+ end
11
+ require 'protobuf'
12
+ require 'protobuf/compiler/compiler'
13
+
14
+
15
+ options = {
16
+ :proto_path => '.',
17
+ :out => '.',
18
+ }
19
+ opts = OptionParser.new("#{$0} [OPTIONS] PROTO_FILE")
20
+ opts.on('-p', '--proto_path <PATH>', 'Specify the directory in which to search for imports. The current directory is default.'){|v| options[:proto_path] = v}
21
+ opts.on('-o', '--out <OUT_DIR>', 'Specify the directory in which Ruby source file is generated. The current directory is default.'){|v| options[:out] = v}
22
+ opts.on_tail('-v', '--version', 'Show version.'){ puts(opts.ver); exit }
23
+ opts.on_tail('-h', '--help', 'Show this message.'){ puts(opts.help); exit }
24
+
25
+ ::Version = Protobuf::VERSION
26
+
27
+ begin
28
+ opts.order!
29
+ rescue OptionParser::ParseError
30
+ $stderr.puts $!.to_s
31
+ exit 1
32
+ end
33
+
34
+ unless ARGV.size > 0
35
+ puts opts
36
+ exit
37
+ end
38
+
39
+ begin
40
+ ARGV.each do |proto_file|
41
+ Protobuf::Compiler.compile(proto_file, options[:proto_path], options[:out])
42
+ end
43
+ rescue
44
+ $stderr.puts $!.message
45
+ exit 1
46
+ end
@@ -0,0 +1,55 @@
1
+ ### Generated by rprotoc. DO NOT EDIT!
2
+ ### <proto file: examples/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
+ # }
23
+ #
24
+ # message AddressBook {
25
+ # repeated Person person = 1;
26
+ # }
27
+
28
+ require 'protobuf/message/message'
29
+ require 'protobuf/message/enum'
30
+ require 'protobuf/message/extend'
31
+
32
+ module Tutorial
33
+ class Person < ::Protobuf::Message
34
+ defined_in __FILE__
35
+ required :string, :name, 1
36
+ required :int32, :id, 2
37
+ optional :string, :email, 3
38
+ class PhoneType < ::Protobuf::Enum
39
+ defined_in __FILE__
40
+ MOBILE = 0
41
+ HOME = 1
42
+ WORK = 2
43
+ end
44
+ class PhoneNumber < ::Protobuf::Message
45
+ defined_in __FILE__
46
+ required :string, :number, 1
47
+ optional :PhoneType, :type, 2, :default => :HOME
48
+ end
49
+ repeated :PhoneNumber, :phone, 4
50
+ end
51
+ class AddressBook < ::Protobuf::Message
52
+ defined_in __FILE__
53
+ repeated :Person, :person, 1
54
+ end
55
+ end