Class: ProtocolBuffers::Message
- Inherits:
-
Object
- Object
- ProtocolBuffers::Message
- Defined in:
- lib/protocol_buffers/runtime/message.rb
Overview
Generated Code
This text describes exactly what Ruby code the protocol buffer compiler generates for any given protocol definition. You should read the language guide before reading this document:
code.google.com/apis/protocolbuffers/docs/proto.html
Packages
If a package name is given in the .proto
file, all top-level messages and enums in the file will be defined underneath a module with the same name as the package. The first letter of the package is capitalized if necessary. This applies to message and enum names as well, since Ruby classes and modules must be capitalized.
For example, the following .proto
file:
package wootcakes;
uberWoot { }
Will define a module Wootcakes
and a class Wootcakes::UberWoot
Messages
Given a simple message definition:
Foo {}
The compiler will generate a class called Foo
, which subclasses ProtocolBuffers::Message.
These generated classes are not designed for subclassing.
Ruby message classes have no particular public methods or accessors other than those defined by ProtocolBuffers::Message and those generated for nested fields, messages, and enum types (see below).
A message can be declared inside another message. For example: message Foo { message Bar { } }
In this case, the Bar
class is declared inside the Foo
class, so you can access it as Foo::Bar
(or if in package Baz
, Baz::Foo::Bar
)
Fields
For each field in the message type, the corresponding class has a member with the same name as the field. How you can manipulate the member depends on its type.
Singular Fields
If you have a singular (optional or required) field foo
of any non-message type, you can manipulate the field foo
as if it were a regular object attribute. For example, if foo
‘s type is int32
, you can say:
.foo = 123
puts .foo
Note that setting foo
to a value of the wrong type will raise a TypeError. Setting foo
to a value of the right type, but one that doesn’t fit (such as assigning an out-of-bounds enum value) will raise an ArgumentError.
If foo
is read when it is not set, its value is the default value for that field. To check if foo
is set, call has_foo?
To clear foo
, call message.foo = nil
. For example:
assert(!.has_foo?)
.foo = 123
assert(.has_foo?)
.foo = nil
assert(!.has_foo?)
Singular String Fields
String fields are treated like other singular fields, but note that the default value for string fields is frozen, so it is effectively an immutable string. Attempting to modify this default string will raise a TypeError, so assign a new string to the field instead.
Singular Message Fields
Message types are a bit special, since they are mutable. Accessing an unset message field will return a default instance of the message type. Say you have the following .proto
definition:
Foo {
optional Bar = 1;
}
Bar {
optional int32 i = 1;
}
To set the message field, you can do either of the following:
foo = Foo.new
assert(!foo.)
foo. = Bar.new
assert(foo.)
Or, to set bar, you can simply assign a value directly to a field within bar, and - presto! - foo has a bar field:
foo = Foo.new
assert(!foo.)
foo..i = 1
assert(foo.)
Note that simply reading a field inside bar does not set the field:
foo = Foo.new
assert(!foo.)
puts foo..i
assert(!foo.)
Repeated Fields
Repeated fields are represented as an object that acts like an Array. For example, given this message definition:
Foo {
repeated int32 nums = 1;
}
You can do the following:
foo = Foo.new
foo.nums << 15
foo.nums.push(32)
assert(foo.nums.length == 2)
assert(foo.nums[0] == 15)
assert(foo.nums[1] == 32)
foo.nums.each { |i| puts i }
foo.nums[1] = 56
assert(foo.nums[1] == 56)
To clear a repeated field, call the clear
method, or assign nil to it like a singular field.
foo = Foo.new
foo.nums << 15
foo.nums.push(32)
assert(foo.nums.length == 2)
foo.nums.clear
assert(foo.nums.length == 0)
foo.nums = nil # equivalent to foo.nums.clear
assert(foo.nums.length == 0)
You can assign to a repeated field using an array, or any other object that responds to each
. This will replace the current contents of the repeated field.
foo = Foo.new
foo.nums << 15
foo.nums = [1, 3, 5]
assert(foo.nums.length == 3)
assert(foo.nums.to_a == [1,3,5])
Repeated fields are always set, so foo.has_nums?
will always be true. Repeated fields don’t take up any space in a serialized message if they are empty.
Repeated Message Fields
Repeated message fields work like other repeated fields. For example, given this message definition:
Foo {
repeated Bar = 1;
}
Bar {
optional int32 i = 1;
}
You can do the following:
foo = Foo.new
foo. << Bar.new(:i => 15)
foo. << Bar.new(:i => 32)
assert(foo..length == 2)
assert(foo.[0].i == 15)
assert(foo.[1].i == 32)
foo..each { || puts .i }
foo.[1].i = 56
assert(foo.[1].i == 56)
Enumerations
Enumerations are defined as a module with an integer constant for each valid value. For example, given:
enum Foo {
VALUE_A = 1;
VALUE_B = 5;
VALUE_C = 1234;
}
The following Ruby code will be generated:
module Foo
VALUE_A = 1
VALUE_B = 5
VALUE_C 1234
end
An exception will be thrown if an enum field is assigned a value not in the enum. Right now, this includes throwing an exception while parsing. This may change in the future to match the C++ behavior of treating it as an unknown tag number.
Extensions
Protocol Buffer extensions are not currently supported in this library.
Services
Protocol Buffer service (RPC) definitions are ignored.
Direct Known Subclasses
DescriptorProto, DescriptorProto::ExtensionRange, EnumDescriptorProto, EnumOptions, EnumValueDescriptorProto, EnumValueOptions, ExtensionRange, FieldDescriptorProto, FieldOptions, FileDescriptorProto, FileDescriptorSet, FileOptions, MessageOptions, MethodDescriptorProto, MethodOptions, NamePart, ServiceDescriptorProto, ServiceOptions, UninterpretedOption, UninterpretedOption::NamePart
Class Method Summary collapse
-
.define_field(otype, type, name, tag, opts = {}) ⇒ Object
:NODOC:.
-
.field_for_name(name) ⇒ Object
Find the field for the given attribute name.
-
.field_for_tag(tag) ⇒ Object
Equivalent to fields.
-
.fields ⇒ Object
Returns a hash of { tag => ProtocolBuffers::Field }.
-
.gen_methods! ⇒ Object
Generate the initialize method using reflection, to improve speed.
-
.optional(type, name, tag, opts = {}) ⇒ Object
:NODOC:.
-
.parse(io) ⇒ Object
Shortcut, simply calls self.new.parse(io).
-
.repeated(type, name, tag, opts = {}) ⇒ Object
:NODOC:.
-
.required(type, name, tag, opts = {}) ⇒ Object
:NODOC:.
- .valid?(message) ⇒ Boolean
Instance Method Summary collapse
-
#==(obj) ⇒ Object
Comparison by class and field values.
-
#attributes=(hash = {}) ⇒ Object
Assign values to attributes in bulk.
-
#clear! ⇒ Object
Reset all fields to the default value.
- #default_changed(tag) ⇒ Object
-
#dup ⇒ Object
This is a shallow copy.
-
#each_unknown_field ⇒ Object
yields |tag_int, value| pairs.
-
#fields ⇒ Object
Returns a hash of { tag => ProtocolBuffers::Field }.
-
#initialize(attributes = {}) ⇒ Message
constructor
Create a new Message of this class.
- #inspect ⇒ Object
-
#merge_field(tag, value, field = ) ⇒ Object
:nodoc:.
-
#merge_from(obj) ⇒ Object
Merge the attribute values from
obj
into this Message, which must be of the same class. -
#merge_from_string(string) ⇒ Object
Parse the string into a new Message of this class, and merge it into the current message like
merge_from
. - #notify_on_change(parent, tag) ⇒ Object
-
#parse(io_or_string) ⇒ Object
Parse a Message of this class from the given IO/String.
- #remember_unknown_field(tag_int, value) ⇒ Object
-
#serialize(io) ⇒ Object
Serialize this Message to the given IO stream using the Protocol Buffer wire format.
-
#serialize_to_string ⇒ Object
(also: #to_s)
Serialize this Message to a String and return it.
- #set_value_for_tag(tag, value) ⇒ Object
- #unknown_field_count ⇒ Object
- #valid? ⇒ Boolean
-
#value_for_tag(tag) ⇒ Object
Reflection: get the attribute value for the given tag id.
-
#value_for_tag?(tag) ⇒ Boolean
Reflection: does this Message have the field set?.
Constructor Details
#initialize(attributes = {}) ⇒ Message
Create a new Message of this class.
= MyMessageClass.new(attributes)
# is equivalent to
= MyMessageClass.new
.attributes = attributes
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/protocol_buffers/runtime/message.rb', line 235 def initialize(attributes = {}) @set_fields = [] fields.each do |tag, field| if field.repeated? self.instance_variable_set("@#{field.name}", RepeatedField.new(field)) @set_fields[tag] = true # repeated fields are always "set" else value = field.default_value self.__send__("#{field.name}=", value) @set_fields[tag] = false if field.class == Field::MessageField value.notify_on_change(self, tag) end end end self.attributes = attributes end |
Class Method Details
.define_field(otype, type, name, tag, opts = {}) ⇒ Object
:NODOC:
421 422 423 424 425 426 427 428 429 430 |
# File 'lib/protocol_buffers/runtime/message.rb', line 421 def self.define_field(otype, type, name, tag, opts = {}) # :NODOC: raise("gen_methods! already called, cannot add more fields") if @methods_generated type = type.is_a?(Module) ? type : type.to_sym name = name.to_sym tag = tag.to_i raise("Field already exists for tag: #{tag}") if fields[tag] field = Field.create(self, otype, type, name, tag, opts) fields[tag] = field field.add_methods_to(self) end |
.field_for_name(name) ⇒ Object
Find the field for the given attribute name. Returns a ProtocolBuffers::field
365 366 367 368 369 |
# File 'lib/protocol_buffers/runtime/message.rb', line 365 def self.field_for_name(name) name = name.to_sym field = fields.find { |tag,field| field.name == name } field && field.last end |
.field_for_tag(tag) ⇒ Object
Equivalent to fields
372 373 374 |
# File 'lib/protocol_buffers/runtime/message.rb', line 372 def self.field_for_tag(tag) fields[tag] end |
.fields ⇒ Object
Returns a hash of { tag => ProtocolBuffers::Field }
354 355 356 |
# File 'lib/protocol_buffers/runtime/message.rb', line 354 def self.fields @fields || @fields = {} end |
.gen_methods! ⇒ Object
Generate the initialize method using reflection, to improve speed. This is called by the generated .pb.rb code, it’s not necessary to call this method directly.
490 491 492 493 494 495 |
# File 'lib/protocol_buffers/runtime/message.rb', line 490 def self.gen_methods! # :NODOC: @methods_generated = true # these generated methods have gone away for now -- the infrastructure has # been left in place, since they'll probably make their way back in at # some point. end |
.optional(type, name, tag, opts = {}) ⇒ Object
:NODOC:
437 438 439 |
# File 'lib/protocol_buffers/runtime/message.rb', line 437 def self.optional(type, name, tag, opts = {}) # :NODOC: define_field(:optional, type, name, tag, opts) end |
.parse(io) ⇒ Object
Shortcut, simply calls self.new.parse(io)
295 296 297 |
# File 'lib/protocol_buffers/runtime/message.rb', line 295 def self.parse(io) self.new.parse(io) end |
.repeated(type, name, tag, opts = {}) ⇒ Object
:NODOC:
441 442 443 |
# File 'lib/protocol_buffers/runtime/message.rb', line 441 def self.repeated(type, name, tag, opts = {}) # :NODOC: define_field(:repeated, type, name, tag, opts) end |
.required(type, name, tag, opts = {}) ⇒ Object
:NODOC:
432 433 434 435 |
# File 'lib/protocol_buffers/runtime/message.rb', line 432 def self.required(type, name, tag, opts = {}) # :NODOC: define_field(:required, type, name, tag, opts) @has_required_field = true end |
.valid?(message) ⇒ Boolean
462 463 464 465 466 467 468 469 470 |
# File 'lib/protocol_buffers/runtime/message.rb', line 462 def self.valid?() return true unless @has_required_field fields.each do |tag, field| if field.otype == :required return false unless .value_for_tag?(tag) end end end |
Instance Method Details
#==(obj) ⇒ Object
Comparison by class and field values.
330 331 332 333 334 335 336 |
# File 'lib/protocol_buffers/runtime/message.rb', line 330 def ==(obj) return false unless obj.is_a?(self.class) fields.each do |tag, field| return false unless self.__send__(field.name) == obj.__send__(field.name) end return true end |
#attributes=(hash = {}) ⇒ Object
Assign values to attributes in bulk.
message.attributes = { :field1 => value1, :field2 => value2 } -> message
322 323 324 325 326 327 |
# File 'lib/protocol_buffers/runtime/message.rb', line 322 def attributes=(hash = {}) hash.each do |name, value| self.send("#{name}=", value) end self end |
#clear! ⇒ Object
Reset all fields to the default value.
339 340 341 |
# File 'lib/protocol_buffers/runtime/message.rb', line 339 def clear! fields.each { |tag, field| self.__send__("#{field.name}=", nil) } end |
#default_changed(tag) ⇒ Object
450 451 452 453 454 455 456 |
# File 'lib/protocol_buffers/runtime/message.rb', line 450 def default_changed(tag) @set_fields[tag] = true if @parent_for_notify @parent_for_notify.default_changed(@tag_for_notify) @parent_for_notify = @tag_for_notify = nil end end |
#dup ⇒ Object
This is a shallow copy.
344 345 346 347 348 349 350 351 |
# File 'lib/protocol_buffers/runtime/message.rb', line 344 def dup ret = self.class.new fields.each do |tag, field| val = self.__send__(field.name) ret.__send__("#{field.name}=", val) end return ret end |
#each_unknown_field ⇒ Object
yields |tag_int, value| pairs
478 479 480 481 |
# File 'lib/protocol_buffers/runtime/message.rb', line 478 def each_unknown_field # :nodoc: return unless @unknown_fields @unknown_fields.each { |tag_int, value| yield tag_int, value } end |
#fields ⇒ Object
Returns a hash of { tag => ProtocolBuffers::Field }
359 360 361 |
# File 'lib/protocol_buffers/runtime/message.rb', line 359 def fields self.class.fields end |
#inspect ⇒ Object
398 399 400 401 402 403 404 405 406 |
# File 'lib/protocol_buffers/runtime/message.rb', line 398 def inspect ret = ProtocolBuffers.bin_sio ret << "#<#{self.class.name}" fields.each do |tag, field| ret << " #{field.name}=#{field.inspect_value(self.__send__(field.name))}" end ret << ">" return ret.string end |
#merge_field(tag, value, field = ) ⇒ Object
:nodoc:
408 409 410 411 412 413 414 415 416 417 418 419 |
# File 'lib/protocol_buffers/runtime/message.rb', line 408 def merge_field(tag, value, field = fields[tag]) # :nodoc: if field.repeated? if value.is_a?(Array) self.__send__("#{field.name}=", self.__send__(field.name) + value) else self.__send__(field.name) << value end else self.__send__("#{field.name}=", value) @set_fields[tag] = true end end |
#merge_from(obj) ⇒ Object
Merge the attribute values from obj
into this Message, which must be of the same class.
Singular fields will be overwritten, except for embedded messages which will be merged. Repeated fields will be concatenated.
304 305 306 307 308 309 310 311 |
# File 'lib/protocol_buffers/runtime/message.rb', line 304 def merge_from(obj) raise(ArgumentError, "Incompatible merge types: #{self.class} and #{obj.class}") unless obj.is_a?(self.class) for tag, field in self.class.fields next unless obj.value_for_tag?(tag) value = obj.value_for_tag(tag) merge_field(tag, value, field) end end |
#merge_from_string(string) ⇒ Object
Parse the string into a new Message of this class, and merge it into the current message like merge_from
.
315 316 317 |
# File 'lib/protocol_buffers/runtime/message.rb', line 315 def merge_from_string(string) merge_from(self.class.new.parse(string)) end |
#notify_on_change(parent, tag) ⇒ Object
445 446 447 448 |
# File 'lib/protocol_buffers/runtime/message.rb', line 445 def notify_on_change(parent, tag) @parent_for_notify = parent @tag_for_notify = tag end |
#parse(io_or_string) ⇒ Object
Parse a Message of this class from the given IO/String. Since Protocol Buffers are not length delimited, this will read until the end of the stream.
This does not call clear! beforehand, so this is logically equivalent to
= self.class.new
.parse(io)
merge_from()
285 286 287 288 289 290 291 292 |
# File 'lib/protocol_buffers/runtime/message.rb', line 285 def parse(io_or_string) io = io_or_string if io.is_a?(String) io = ProtocolBuffers.bin_sio(io) end Decoder.decode(io, self) return self end |
#remember_unknown_field(tag_int, value) ⇒ Object
472 473 474 475 |
# File 'lib/protocol_buffers/runtime/message.rb', line 472 def remember_unknown_field(tag_int, value) @unknown_fields || @unknown_fields = [] @unknown_fields << [tag_int, value] end |
#serialize(io) ⇒ Object
Serialize this Message to the given IO stream using the Protocol Buffer wire format.
Equivalent to, but more efficient than
io <<
Returns io
263 264 265 266 |
# File 'lib/protocol_buffers/runtime/message.rb', line 263 def serialize(io) Encoder.encode(io, self) io end |
#serialize_to_string ⇒ Object Also known as: to_s
Serialize this Message to a String and return it.
269 270 271 272 273 |
# File 'lib/protocol_buffers/runtime/message.rb', line 269 def serialize_to_string sio = ProtocolBuffers.bin_sio serialize(sio) return sio.string end |
#set_value_for_tag(tag, value) ⇒ Object
385 386 387 |
# File 'lib/protocol_buffers/runtime/message.rb', line 385 def set_value_for_tag(tag, value) self.__send__("#{fields[tag].name}=", value) end |
#unknown_field_count ⇒ Object
483 484 485 |
# File 'lib/protocol_buffers/runtime/message.rb', line 483 def unknown_field_count (@unknown_fields || []).size end |
#valid? ⇒ Boolean
458 459 460 |
# File 'lib/protocol_buffers/runtime/message.rb', line 458 def valid? self.class.valid?(self) end |
#value_for_tag(tag) ⇒ Object
Reflection: get the attribute value for the given tag id.
.value_for_tag(.class.field_for_name(:f1).tag)
# is equivalent to
.f1
381 382 383 |
# File 'lib/protocol_buffers/runtime/message.rb', line 381 def value_for_tag(tag) self.__send__(fields[tag].name) end |
#value_for_tag?(tag) ⇒ Boolean
Reflection: does this Message have the field set?
.value_for_tag?(.class.field_for_name(:f1).tag)
# is equivalent to
.has_f1?
394 395 396 |
# File 'lib/protocol_buffers/runtime/message.rb', line 394 def value_for_tag?(tag) @set_fields[tag] || false end |