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.
-
#fields ⇒ Object
Returns a hash of { tag => ProtocolBuffers::Field }.
- #fully_qualified_name ⇒ 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
objinto 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:
430 431 432 433 434 435 436 437 438 |
# File 'lib/protocol_buffers/runtime/message.rb', line 430 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
369 370 371 372 373 |
# File 'lib/protocol_buffers/runtime/message.rb', line 369 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
376 377 378 |
# File 'lib/protocol_buffers/runtime/message.rb', line 376 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 |
.fully_qualified_name ⇒ Object
470 471 472 |
# File 'lib/protocol_buffers/runtime/message.rb', line 470 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
519 520 521 |
# File 'lib/protocol_buffers/runtime/message.rb', line 519 def self.gen_methods! # :NODOC: @methods_generated = true end |
.initial_set_fields ⇒ Object
358 359 360 |
# File 'lib/protocol_buffers/runtime/message.rb', line 358 def self.initial_set_fields @set_fields ||= [] end |
.optional(type, name, tag, opts = {}) ⇒ Object
:NODOC:
445 446 447 |
# File 'lib/protocol_buffers/runtime/message.rb', line 445 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:
449 450 451 |
# File 'lib/protocol_buffers/runtime/message.rb', line 449 def self.repeated(type, name, tag, opts = {}) # :NODOC: define_field(:repeated, type, name, tag, opts) end |
.required(type, name, tag, opts = {}) ⇒ Object
:NODOC:
440 441 442 443 |
# File 'lib/protocol_buffers/runtime/message.rb', line 440 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
466 467 468 |
# File 'lib/protocol_buffers/runtime/message.rb', line 466 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
482 483 484 485 486 487 488 489 490 491 492 493 |
# File 'lib/protocol_buffers/runtime/message.rb', line 482 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
499 500 501 |
# File 'lib/protocol_buffers/runtime/message.rb', line 499 def self.validate!() valid?(, true) 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
458 459 460 461 462 463 464 |
# File 'lib/protocol_buffers/runtime/message.rb', line 458 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
509 510 511 512 |
# File 'lib/protocol_buffers/runtime/message.rb', line 509 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 }
363 364 365 |
# File 'lib/protocol_buffers/runtime/message.rb', line 363 def fields self.class.fields end |
#fully_qualified_name ⇒ Object
474 475 476 |
# File 'lib/protocol_buffers/runtime/message.rb', line 474 def fully_qualified_name self.class.fully_qualified_name end |
#inspect ⇒ Object
402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
# File 'lib/protocol_buffers/runtime/message.rb', line 402 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:
417 418 419 420 421 422 423 424 425 426 427 428 |
# File 'lib/protocol_buffers/runtime/message.rb', line 417 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
453 454 455 456 |
# File 'lib/protocol_buffers/runtime/message.rb', line 453 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
503 504 505 506 |
# File 'lib/protocol_buffers/runtime/message.rb', line 503 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
389 390 391 |
# File 'lib/protocol_buffers/runtime/message.rb', line 389 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
514 515 516 |
# File 'lib/protocol_buffers/runtime/message.rb', line 514 def unknown_field_count (@unknown_fields || []).size end |
#valid? ⇒ Boolean
478 479 480 |
# File 'lib/protocol_buffers/runtime/message.rb', line 478 def valid? self.class.valid?(self) end |
#validate! ⇒ Object
495 496 497 |
# File 'lib/protocol_buffers/runtime/message.rb', line 495 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
385 386 387 |
# File 'lib/protocol_buffers/runtime/message.rb', line 385 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?
398 399 400 |
# File 'lib/protocol_buffers/runtime/message.rb', line 398 def value_for_tag?(tag) @set_fields[tag] || false end |