Skip to content

Compiling Definitions

Manh DV edited this page Oct 7, 2019 · 5 revisions

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!

Let's say you have a definitions/foo/user.proto file that defines a User message.

- definitions
  |- foo
      |- user.proto
// definitions/foo/user.proto
package foo;
message User {
  optional string first_name = 1;
  optional string last_name = 2;
}

Now let's compile that definition to ruby:

$ protoc -I ./definitions --ruby_out ./lib definitions/foo/user.proto

The previous line will take whatever is defined in user.proto and output ruby classes to the ./lib directory, obeying the package directive. Your ./lib should now look like this:

- lib
  |- foo
      |- user.pb.rb

The generated file user.pb.rb should look something like this:

# lib/foo/user.pb.rb
module Foo
  class User < ::Protobuf::Message; end

  class User
    optional :string, :first_name, 1
    optional :string, :last_name, 2
  end
end

Note: The generator will pre-define all message/enum classes empty and then re-open to apply the defined fields. This is to prevent circular field dependency issues.

The generated class is now just a plain old ruby object. You can use it however you wish. Recognize that you can also compile multiple protos at the same time, just use shell glob syntax.

$ protoc -I ./definitions --ruby_out ./lib definitions/**/*.proto

Compiling with rake

This library now provides compiler rake tasks that you can use directly or inherit from your own tasks. The simplest solution is to simply load our compile.rake task file in your Rakefile and you should automatically get a compile and a clean task.

# Rakefile
load 'protobuf/tasks/compile.rake'
$ bundle exec rake -T
...
protobuf:compile
protobuf:clean
...

# Only the first argument is required.
$ bx rake protobuf:compile[my_base_package]
$ bx rake protobuf:compile[my_base_package] PB_NO_CLEAN=1
$ bx rake protobuf:compile[my_base_package, src, defs, my-crazy-plugin, '.fuby']

The compile task takes one to five arguments. The first argument, the package is the base package defined in your protos. The other 4 arguments, with their defaults, are as follows (in this order):

args.with_defaults(:source => 'definitions')
args.with_defaults(:destination => 'lib')
args.with_defaults(:plugin => 'ruby')
args.with_defaults(:file_extension => '.pb.rb')

The compile by default will force a clean using the same arguments you passed to compile. To avoid cleaning before the compile use the environment variable PB_NO_CLEAN=1.


The clean task accepts 1 to 3 arguments. The only required argument is the base package (just like the compile task). You can clean without prompt (force clean) by passing PB_FORCE_CLEAN=1.

args.with_defaults(:destination => 'lib')
args.with_defaults(:file_extension => '.pb.rb')
# Only the first argument is required.
$ bx rake protobuf:clean[my_base_package]
$ bx rake protobuf:clean[my_base_package] PB_FORCE_CLEAN=1
$ bx rake protobuf:clean[my_base_package, src, '.fuby']

You can also invoke these tasks via Rake's ruby API to provide sensible defaults for your project. This is nothing special about our tasks of course, it's just Rake.

# Rakefile
load 'protobuf/tasks/compile.rake'

task :compile do
  # do some stuff before compile

  # Invoke the protobuf compile task with your sensible defaults
  ::Rake::Task['protobuf:compile'].invoke('my_base_package', 'src', 'defs', 'my-crazy-plugin', '.fuby')

  # Make sure you "reenable" the compile task if you plan to call it again...
  ::Rake::Task['protobuf:compile'].reenable

  # Call the compile again with other args
  ::Rake::Task['protobuf:compile'].invoke('martian_pkg', 'martian_src', '../martians/defs', 'martian-plugin', '.martians.rb')

  # do some stuff after compile
end

task :clean do
  # ...
end

Next: Messages & Enums
Back: Installation

Clone this wiki locally