Class: Pbbuilder
- Inherits:
-
Object
- Object
- Pbbuilder
- Defined in:
- lib/pbbuilder.rb,
lib/pbbuilder/errors.rb,
lib/pbbuilder/railtie.rb,
lib/pbbuilder/collection_renderer.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: CollectionRenderer, MergeError, Railtie
Instance Method Summary collapse
- #attributes! ⇒ Object
- #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
- #new_message_for(field) ⇒ 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.
33 34 35 36 37 |
# File 'lib/pbbuilder.rb', line 33 def initialize() = yield self if ::Kernel.block_given? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing ⇒ Object
39 40 41 |
# File 'lib/pbbuilder.rb', line 39 def method_missing(...) set!(...) end |
Instance Method Details
#attributes! ⇒ Object
43 44 45 |
# File 'lib/pbbuilder.rb', line 43 def attributes! .to_h end |
#extract!(element, *args) ⇒ Object
120 121 122 |
# File 'lib/pbbuilder.rb', line 120 def extract!(element, *args) args.each { |arg| [arg.to_s] = element.send(arg) } end |
#merge!(object) ⇒ Object
Merges object into a protobuf message, mainly used for caching.
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/pbbuilder.rb', line 127 def merge!(object) ::Kernel.raise Pbbuilder::MergeError.build(target!, object) unless object.class == ::Hash object.each do |key, value| next if value.respond_to?(:empty?) && value.empty? descriptor = _descriptor_for_field(key) ::Kernel.raise ::ArgumentError, "Unknown field #{key}" if descriptor.nil? if descriptor.label == :repeated # optional empty fields don't show up in @message object, # we recreate empty message, so we can fill it with values if [key.to_s].nil? [key.to_s] = (descriptor) end if value.respond_to?(:to_hash) value.to_hash.each {|k, v| [key.to_s][k] = v} elsif value.respond_to?(:to_ary) elements = value.map do |obj| descriptor.subtype ? descriptor.subtype.msgclass.new(obj) : obj end [key.to_s].replace(elements) end else if descriptor.type == :message [key.to_s] = descriptor.subtype.msgclass.new(value) else # pb.fields {"one" => "two"} # pb.boolean true || false # pb.field_name do # pb.tags ["ok", "cool"] # end [key.to_s] = value end end end end |
#new_message_for(field) ⇒ Object
173 174 175 176 177 178 |
# File 'lib/pbbuilder.rb', line 173 def (field) descriptor = _descriptor_for_field(field) ::Kernel.raise ::ArgumentError, "Unknown field #{field}" if descriptor.nil? (descriptor) end |
#respond_to_missing?(field) ⇒ Boolean
47 48 49 |
# File 'lib/pbbuilder.rb', line 47 def respond_to_missing?(field) !!_descriptor_for_field(field) end |
#set!(field, *args, &block) ⇒ Object
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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/pbbuilder.rb', line 51 def set!(field, *args, &block) name = field.to_s descriptor = _descriptor_for_field(name) ::Kernel.raise ::ArgumentError, "Unknown field #{name}" if descriptor.nil? if ::Kernel.block_given? ::Kernel.raise ::ArgumentError, "can't pass block to non-message field" unless descriptor.type == :message if descriptor.label == :repeated # example syntax that should end up here: # 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) else # example syntax that should end up here: # pb.field { pb.name "hello" } ::Kernel.raise ::ArgumentError, "wrong number of arguments (expected 0)" unless args.empty? = ([name] ||= (descriptor)) _scope(, &block) end elsif args.length == 1 arg = args.first if descriptor.label == :repeated if arg.respond_to?(:to_hash) # example syntax that should end up here: # pb.fields {"one" => "two"} arg.to_hash.each { |k, v| [name][k] = v } elsif arg.respond_to?(:to_ary) && !descriptor.type.eql?(:message) # pb.fields ["one", "two"] [name].replace arg.to_ary elsif arg.respond_to?(:to_ary) && descriptor.type.eql?(:message) # example syntax that should end up here: # pb.friends [Person.new(name: "Johnny Test"), Person.new(name: "Max Verstappen")] args.flatten.each {|obj| [name].push descriptor.subtype.msgclass.new(obj)} else # example syntax that should end up here: # pb.fields "one" [name].replace [arg] end else # example syntax that should end up here: # pb.field "value" [name] = arg end else # example syntax that should end up here: # 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.
169 170 171 |
# File 'lib/pbbuilder.rb', line 169 def target! end |