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. If an unknown enum value is found while parsing a message, this is treated like an unknown tag id. This matches the C++ library behavior.
Extensions
Protocol Buffer extensions are not currently supported in this library.
Services
Protocol Buffer service (RPC) definitions are ignored.
Direct Known Subclasses
CodeGeneratorRequest, CodeGeneratorResponse, CodeGeneratorResponse::File, Google::Protobuf::DescriptorProto, Google::Protobuf::DescriptorProto::ExtensionRange, Google::Protobuf::EnumDescriptorProto, Google::Protobuf::EnumOptions, Google::Protobuf::EnumValueDescriptorProto, Google::Protobuf::EnumValueOptions, Google::Protobuf::FieldDescriptorProto, Google::Protobuf::FieldOptions, Google::Protobuf::FileDescriptorProto, Google::Protobuf::FileDescriptorSet, Google::Protobuf::FileOptions, Google::Protobuf::MessageOptions, Google::Protobuf::MethodDescriptorProto, Google::Protobuf::MethodOptions, Google::Protobuf::ServiceDescriptorProto, Google::Protobuf::ServiceOptions, Google::Protobuf::SourceCodeInfo, Google::Protobuf::SourceCodeInfo::Location, Google::Protobuf::UninterpretedOption, Google::Protobuf::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 }.
- .fully_qualified_name ⇒ Object
-
.gen_methods! ⇒ Object
left in for compatibility with previously created .pb.rb files – no longer used.
- .initial_set_fields ⇒ Object
-
.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:.
- .set_fully_qualified_name(name) ⇒ Object
- .to_hash(message) ⇒ Object
- .valid?(message, raise_exception = false) ⇒ Boolean
- .validate!(message) ⇒ Object
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.
-
#eql?(obj) ⇒ Boolean
Comparison by class and field values.
-
#fields ⇒ Object
Returns a hash of { tag => ProtocolBuffers::Field }.
- #fully_qualified_name ⇒ Object
- #hash ⇒ Object
-
#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
- #to_hash ⇒ Object
- #unknown_field_count ⇒ Object
- #valid? ⇒ Boolean
- #validate! ⇒ Object
-
#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
234 235 236 237 |
# File 'lib/protocol_buffers/runtime/message.rb', line 234 def initialize(attributes = {}) @set_fields = self.class.initial_set_fields.dup self.attributes = attributes end |
Class Method Details
.define_field(otype, type, name, tag, opts = {}) ⇒ Object
:NODOC:
457 458 459 460 461 462 463 464 465 |
# File 'lib/protocol_buffers/runtime/message.rb', line 457 def self.define_field(otype, type, name, tag, opts = {}) # :NODOC: 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
396 397 398 399 400 |
# File 'lib/protocol_buffers/runtime/message.rb', line 396 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
403 404 405 |
# File 'lib/protocol_buffers/runtime/message.rb', line 403 def self.field_for_tag(tag) fields[tag] end |
.fields ⇒ Object
Returns a hash of { tag => ProtocolBuffers::Field }
381 382 383 |
# File 'lib/protocol_buffers/runtime/message.rb', line 381 def self.fields @fields || @fields = {} end |
.fully_qualified_name ⇒ Object
497 498 499 |
# File 'lib/protocol_buffers/runtime/message.rb', line 497 def self.fully_qualified_name @fully_qualified_name end |
.gen_methods! ⇒ Object
left in for compatibility with previously created .pb.rb files – no longer used
546 547 548 |
# File 'lib/protocol_buffers/runtime/message.rb', line 546 def self.gen_methods! # :NODOC: @methods_generated = true end |
.initial_set_fields ⇒ Object
385 386 387 |
# File 'lib/protocol_buffers/runtime/message.rb', line 385 def self.initial_set_fields @set_fields ||= [] end |
.optional(type, name, tag, opts = {}) ⇒ Object
:NODOC:
472 473 474 |
# File 'lib/protocol_buffers/runtime/message.rb', line 472 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:
476 477 478 |
# File 'lib/protocol_buffers/runtime/message.rb', line 476 def self.repeated(type, name, tag, opts = {}) # :NODOC: define_field(:repeated, type, name, tag, opts) end |
.required(type, name, tag, opts = {}) ⇒ Object
:NODOC:
467 468 469 470 |
# File 'lib/protocol_buffers/runtime/message.rb', line 467 def self.required(type, name, tag, opts = {}) # :NODOC: define_field(:required, type, name, tag, opts) @has_required_field = true end |
.set_fully_qualified_name(name) ⇒ Object
493 494 495 |
# File 'lib/protocol_buffers/runtime/message.rb', line 493 def self.set_fully_qualified_name(name) @fully_qualified_name = name.dup.freeze end |
.to_hash(message) ⇒ Object
264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/protocol_buffers/runtime/message.rb', line 264 def self.to_hash() return nil if == nil return .is_a?(String) ? .dup : unless .is_a?(::ProtocolBuffers::Message) .fields.select do |tag, field| .value_for_tag?(tag) end.inject(Hash.new) do |hash, (tag, field)| value = .value_for_tag(tag) hash[field.name] = value.is_a?(::ProtocolBuffers::RepeatedField) ? value.map { |elem| to_hash(elem) } : to_hash(value) hash end end |
.valid?(message, raise_exception = false) ⇒ Boolean
509 510 511 512 513 514 515 516 517 518 519 520 |
# File 'lib/protocol_buffers/runtime/message.rb', line 509 def self.valid?(, raise_exception=false) return true unless @has_required_field fields.each do |tag, field| next if field.otype != :required next if .value_for_tag?(tag) && (field.class != Field::MessageField || .value_for_tag(tag).valid?) return false unless raise_exception raise(ProtocolBuffers::EncodeError.new(field), "Required field '#{field.name}' is invalid") end true end |
.validate!(message) ⇒ Object
526 527 528 |
# File 'lib/protocol_buffers/runtime/message.rb', line 526 def self.validate!() valid?(, true) end |
Instance Method Details
#==(obj) ⇒ Object
Comparison by class and field values.
330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/protocol_buffers/runtime/message.rb', line 330 def ==(obj) return false unless obj.is_a?(self.class) fields.each do |tag, _| if value_for_tag?(tag) return false unless (obj.value_for_tag?(tag) && value_for_tag(tag) == obj.value_for_tag(tag)) else return false if obj.value_for_tag?(tag) end 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.
366 367 368 |
# File 'lib/protocol_buffers/runtime/message.rb', line 366 def clear! fields.each { |tag, field| self.__send__("#{field.name}=", nil) } end |
#default_changed(tag) ⇒ Object
485 486 487 488 489 490 491 |
# File 'lib/protocol_buffers/runtime/message.rb', line 485 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.
371 372 373 374 375 376 377 378 |
# File 'lib/protocol_buffers/runtime/message.rb', line 371 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
536 537 538 539 |
# File 'lib/protocol_buffers/runtime/message.rb', line 536 def each_unknown_field # :nodoc: return unless @unknown_fields @unknown_fields.each { |tag_int, value| yield tag_int, value } end |
#eql?(obj) ⇒ Boolean
Comparison by class and field values.
343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/protocol_buffers/runtime/message.rb', line 343 def eql?(obj) return false unless obj.is_a?(self.class) fields.each do |tag, _| if value_for_tag?(tag) return false unless (obj.value_for_tag?(tag) && value_for_tag(tag).eql?(obj.value_for_tag(tag))) else return false if obj.value_for_tag?(tag) end end return true end |
#fields ⇒ Object
Returns a hash of { tag => ProtocolBuffers::Field }
390 391 392 |
# File 'lib/protocol_buffers/runtime/message.rb', line 390 def fields self.class.fields end |
#fully_qualified_name ⇒ Object
501 502 503 |
# File 'lib/protocol_buffers/runtime/message.rb', line 501 def fully_qualified_name self.class.fully_qualified_name end |
#hash ⇒ Object
355 356 357 358 359 360 361 362 363 |
# File 'lib/protocol_buffers/runtime/message.rb', line 355 def hash hash_code = 0 fields.each do |tag, _| if value_for_tag?(tag) hash_code = hash_code ^ value_for_tag(tag).hash end end hash_code end |
#inspect ⇒ Object
429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/protocol_buffers/runtime/message.rb', line 429 def inspect ret = ProtocolBuffers.bin_sio ret << "#<#{self.class.name}" fields.each do |tag, field| if value_for_tag?(tag) value = field.inspect_value(self.__send__(field.name)) else value = "<unset>" end ret << " #{field.name}=#{value}" end ret << ">" return ret.string end |
#merge_field(tag, value, field = ) ⇒ Object
:nodoc:
444 445 446 447 448 449 450 451 452 453 454 455 |
# File 'lib/protocol_buffers/runtime/message.rb', line 444 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
480 481 482 483 |
# File 'lib/protocol_buffers/runtime/message.rb', line 480 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
530 531 532 533 |
# File 'lib/protocol_buffers/runtime/message.rb', line 530 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
247 248 249 250 |
# File 'lib/protocol_buffers/runtime/message.rb', line 247 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.
253 254 255 256 257 |
# File 'lib/protocol_buffers/runtime/message.rb', line 253 def serialize_to_string sio = ProtocolBuffers.bin_sio serialize(sio) return sio.string end |
#set_value_for_tag(tag, value) ⇒ Object
416 417 418 |
# File 'lib/protocol_buffers/runtime/message.rb', line 416 def set_value_for_tag(tag, value) self.__send__("#{fields[tag].name}=", value) end |
#to_hash ⇒ Object
260 261 262 |
# File 'lib/protocol_buffers/runtime/message.rb', line 260 def to_hash self.class.to_hash(self) end |
#unknown_field_count ⇒ Object
541 542 543 |
# File 'lib/protocol_buffers/runtime/message.rb', line 541 def unknown_field_count (@unknown_fields || []).size end |
#valid? ⇒ Boolean
505 506 507 |
# File 'lib/protocol_buffers/runtime/message.rb', line 505 def valid? self.class.valid?(self) end |
#validate! ⇒ Object
522 523 524 |
# File 'lib/protocol_buffers/runtime/message.rb', line 522 def validate! self.class.validate!(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
412 413 414 |
# File 'lib/protocol_buffers/runtime/message.rb', line 412 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?
425 426 427 |
# File 'lib/protocol_buffers/runtime/message.rb', line 425 def value_for_tag?(tag) @set_fields[tag] || false end |