class Pbbuilder
Pbbuilder
makes it easy to create a protobuf message using the builder pattern It is heavily inspired by jbuilder
Given this example message definition: message Person {
string name = 1; repeated Person friends = 2;
}
You could use Pbbuilder
as follows: person = RPC::Person.new Pbbuilder.new(person)
do |pb|
pb.name "Hello" pb.friends [1, 2, 3] do |number| pb.name "Friend ##{number}" end
end
message.name => “Hello”
It basically works exactly like jbuilder. The main difference is that it can use introspection to figure out what kind of protobuf message it needs to create.
Public Class Methods
new(message) { |self| ... }
click to toggle source
# File lib/pbbuilder.rb, line 25 def initialize(message) @message = message yield self if ::Kernel.block_given? end
Public Instance Methods
extract!(element, *args)
click to toggle source
# File lib/pbbuilder.rb, line 97 def extract!(element, *args) args.each do |arg| value = element.send(arg) @message[arg.to_s] = value end end
method_missing(...)
click to toggle source
# File lib/pbbuilder.rb, line 31 def method_missing(...) set!(...) end
respond_to_missing?(field)
click to toggle source
# File lib/pbbuilder.rb, line 35 def respond_to_missing?(field) !!@message.class.descriptor.lookup(field.to_s) end
set!(field, *args, &block)
click to toggle source
# File lib/pbbuilder.rb, line 39 def set!(field, *args, &block) name = field.to_s descriptor = @message.class.descriptor.lookup(name) ::Kernel.raise ::ArgumentError, "Unknown field #{name}" if descriptor.nil? if block ::Kernel.raise ::ArgumentError, "can't pass block to non-message field" unless descriptor.type == :message if descriptor.label == :repeated # pb.field @array { |element| pb.name element.name } ::Kernel.raise ::ArgumentError, "wrong number of arguments #{args.length} (expected 1)" unless args.length == 1 collection = args.first _append_repeated(name, descriptor, collection, &block) return end ::Kernel.raise ::ArgumentError, "wrong number of arguments (expected 0)" unless args.empty? # pb.field { pb.name "hello" } message = (@message[name] ||= _new_message_from_descriptor(descriptor)) _scope(message, &block) elsif args.length == 1 arg = args.first if descriptor.label == :repeated if arg.respond_to?(:to_hash) # pb.fields {"one" => "two"} arg.to_hash.each do |k, v| @message[name][k] = v end elsif arg.respond_to?(:to_ary) # pb.fields ["one", "two"] # Using concat so it behaves the same as _append_repeated @message[name].concat arg.to_ary else # pb.fields "one" @message[name].push arg end else # pb.field "value" @message[name] = arg end else # pb.field @value, :id, :name, :url element = args.shift if descriptor.label == :repeated # If the message field that's being assigned is a repeated field, then we assume that `element` is enumerable. # This way you can do something like pb.repeated_field @array, :id, :name # This will create a message out of every object in @array, copying over the :id and :name values. set!(name, element) do |item| extract!(item, *args) end else set!(name) do extract!(element, *args) end end end end
target!()
click to toggle source
# File lib/pbbuilder.rb, line 104 def target! @message end
Private Instance Methods
_append_repeated(name, descriptor, collection, &block)
click to toggle source
# File lib/pbbuilder.rb, line 110 def _append_repeated(name, descriptor, collection, &block) ::Kernel.raise ::ArgumentError, "expected Enumerable" unless collection.respond_to?(:map) elements = collection.map do |element| message = _new_message_from_descriptor(descriptor) _scope(message) { block.call(element) } end @message[name].push(*elements) end
_new_message_from_descriptor(descriptor)
click to toggle source
# File lib/pbbuilder.rb, line 129 def _new_message_from_descriptor(descriptor) ::Kernel.raise ::ArgumentError, "can't pass block to non-message field" unless descriptor.type == :message # Here we're using Protobuf reflection to create an instance of the message class message_descriptor = descriptor.subtype message_class = message_descriptor.msgclass message_class.new end
_scope(message) { || ... }
click to toggle source
# File lib/pbbuilder.rb, line 120 def _scope(message) old_message = @message @message = message yield message ensure @message = old_message end