DEPRECATED
This gem hasn't been meaningfully maintained since 2017-2018. The released gem will remain public, but future development is unlikely beyond bumps to dependency versions.
Protip
Relatively painless protocol buffers in Ruby.
Basic Usage
Protip lets you get and set common well-known types in your protobuf messages using high-level Ruby objects.
Given a protobuf message:
message MyMessage {
google.protobuf.StringValue string = 1;
google.protobuf.Timestamp timestamp = 2;
}Manipulate it like:
m = Protip.decorate(MyMessage.new)
m.string = 'bar'
m.string # => 'bar'
m.timestamp = Time.now
m.message # => updated MyMessage objectUsing standard protobuf, you'd have to do something like:
m = MyMessage.new
m.string = Google::Protobuf::StringValue.new(value: 'foo')
m.string.value #=> 'foo'
time = Time.now
message.timestamp = Google::Protobuf::Timestamp.new(
seconds: time.to_i,
nanos: (time.usec * 1000)
)Supported messages
Protip has built-in support for the following well-known types:
google.protobuf.DoubleValuegoogle.protobuf.FloatValuegoogle.protobuf.Int64Valuegoogle.protobuf.UInt64Valuegoogle.protobuf.Int32Valuegoogle.protobuf.UInt32Valuegoogle.protobuf.BoolValuegoogle.protobuf.StringValuegoogle.protobuf.BytesValuegoogle.protobuf.Timestamp
As well as some additional types for enums and repeated-or-nil fields:
-
protip.messages.EnumValue(for nullable enum fields) protip.messages.RepeatedEnumprotip.messages.RepeatedDoubleprotip.messages.RepeatedFloatprotip.messages.RepeatedInt64protip.messages.RepeatedUInt64protip.messages.RepeatedInt32protip.messages.RepeatedUInt32protip.messages.RepeatedBoolprotip.messages.RepeatedStringprotip.messages.RepeatedBytes
To reference these messages in your .proto files, pass the
definitions/ directory to protoc (accessible via
File.join(Gem.loaded_specs['protip'].full_gem_path, 'definitions')
in Ruby) during compilation and use any of:
import "google/protobuf/wrappers.proto";
import "google/protobuf/timestamp.proto";
import "protip/messages.proto";Enum types
protip.messages.EnumValue and protip.messages.RepeatedEnum both
require a custom option to convert between enum symbols and the
integral value used by the message. You can use these types like:
message Foo {
enum Bar { BAZ = 0; }
protip.messages.EnumValue bar = 1 [(protip_enum) = "Foo.Bar"];
}And then, in Ruby:
m = Foo.new
m.bar = :BAZ
m.bar # => :BAZPending resolution of a
protobuf issue, enum
support also requires that you use the protip:compile task provided
in protip/tasks/compile.rake when
compiling your .proto files.
Architecture
Protip.decorate returns a Protip::Decorator object, which
delegates getter/setter calls to its underlying message.
Getters/setters for message fields are filtered through a
Protip::Transformer instance, which defines to_object and
to_message to convert between Ruby objects and representative
protobuf messages.
By default, Protip.default_transformer is used for conversion. You
can add your own message transformations using:
Protip.default_transformer['MyMessage'] = MyTransformer.new
ActiveModel resources
Protip includes support for persistable resources backed by protobuf messages. The API here should be considered experimental.
Define a protobuf message to represent the fields on your resource:
// my_resource_message.proto
message MyResourceMessage {
optional int64 id = 1;
optional string name = 2;
}
Then define your resource and use it like an ActiveModel::Model:
class MyResource
include Protip::Resource
resource actions: [:create, :update, :show, :index],
message: MyResourceMessage
end
resource = MyResource.new(name: 'foo')
if resource.save
puts "Saved with ID: #{resource.id}"
else
puts resource.errors.full_messages.join("\n")
end
Development
To build message classes, you'll need to install the latest version of
protoc.
To use the rbi_out option for sorbet interface file generation you'll need: https://github.com/coinbase/protoc-gen-rbi
Build message classes: rake compile
Run tests: rake test