Class: Pbbuilder
- Inherits:
-
Object
- Object
- Pbbuilder
- Defined in:
- lib/pbbuilder.rb,
lib/pbbuilder/errors.rb,
lib/pbbuilder/railtie.rb
Overview
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.
Direct Known Subclasses
Defined Under Namespace
Classes: MergeError, Railtie
Instance Method Summary collapse
- #extract!(element, *args) ⇒ Object
-
#initialize(message) {|_self| ... } ⇒ Pbbuilder
constructor
A new instance of Pbbuilder.
-
#merge!(object) ⇒ Object
Merges object into a protobuf message, mainly used for caching.
- #method_missing ⇒ Object
- #respond_to_missing?(field) ⇒ Boolean
- #set!(field, *args, &block) ⇒ Object
-
#target! ⇒ Object
Initialized message object.
Constructor Details
#initialize(message) {|_self| ... } ⇒ Pbbuilder
Returns a new instance of Pbbuilder.
31 32 33 34 35 |
# File 'lib/pbbuilder.rb', line 31 def initialize() @message = yield self if ::Kernel.block_given? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing ⇒ Object
37 38 39 |
# File 'lib/pbbuilder.rb', line 37 def method_missing(...) set!(...) end |
Instance Method Details
#extract!(element, *args) ⇒ Object
103 104 105 106 107 108 |
# File 'lib/pbbuilder.rb', line 103 def extract!(element, *args) args.each do |arg| value = element.send(arg) @message[arg.to_s] = value end end |
#merge!(object) ⇒ Object
Merges object into a protobuf message, mainly used for caching.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/pbbuilder.rb', line 113 def merge!(object) ::Kernel.raise Pbbuilder::MergeError.build(target!, object) unless object.class == ::Hash object.each_key do |key| if object[key].respond_to?(:empty?) && object[key].empty? ::Kernel.raise Pbbuilder::MergeError.build(target!, object) end if object[key].class == ::String # pb.fields {"one" => "two"} @message[key.to_s] = object[key] elsif object[key].class == ::Array # pb.tags ['test', 'ok'] @message[key.to_s].replace object[key] elsif object[key].class == ::TrueClass || object[key].class == ::FalseClass # pb.boolean true || false @message[key.to_s] = object[key] elsif ( obj = object[key]).class == ::Hash # pb.field_name do # pb.tags ["ok", "cool"] # end # # optional empty fields don't show up in @message object, # we recreate empty message, so we can fill it with values if @message[key.to_s].nil? field_descriptor = @message.class.descriptor.lookup(key.to_s) @message[key.to_s] = (field_descriptor) end @message[key.to_s] = _scope(@message[key.to_s]) { self.merge!(obj) } end end end |
#respond_to_missing?(field) ⇒ Boolean
41 42 43 |
# File 'lib/pbbuilder.rb', line 41 def respond_to_missing?(field) !!@message.class.descriptor.lookup(field.to_s) end |
#set!(field, *args, &block) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/pbbuilder.rb', line 45 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[name] ||= (descriptor)) _scope(, &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! ⇒ Object
Returns Initialized message object.
149 150 151 |
# File 'lib/pbbuilder.rb', line 149 def target! @message end |