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, DescriptorProto, DescriptorProto::ExtensionRange, EnumDescriptorProto, EnumOptions, EnumValueDescriptorProto, EnumValueOptions, FieldDescriptorProto, FieldOptions, FileDescriptorProto, FileDescriptorSet, FileOptions, MessageOptions, MethodDescriptorProto, MethodOptions, ServiceDescriptorProto, ServiceOptions, SourceCodeInfo, SourceCodeInfo::Location, 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
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:.
- .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 }.
-
#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
- #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:
414 415 416 417 418 419 420 421 422 |
# File 'lib/protocol_buffers/runtime/message.rb', line 414 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
353 354 355 356 357 |
# File 'lib/protocol_buffers/runtime/message.rb', line 353 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
360 361 362 |
# File 'lib/protocol_buffers/runtime/message.rb', line 360 def self.field_for_tag(tag) fields[tag] end |
.fields ⇒ Object
Returns a hash of { tag => ProtocolBuffers::Field }
338 339 340 |
# File 'lib/protocol_buffers/runtime/message.rb', line 338 def self.fields @fields || @fields = {} end |
.gen_methods! ⇒ Object
left in for compatibility with previously created .pb.rb files – no longer used
491 492 493 |
# File 'lib/protocol_buffers/runtime/message.rb', line 491 def self.gen_methods! # :NODOC: @methods_generated = true end |
.initial_set_fields ⇒ Object
342 343 344 |
# File 'lib/protocol_buffers/runtime/message.rb', line 342 def self.initial_set_fields @set_fields ||= [] end |
.optional(type, name, tag, opts = {}) ⇒ Object
:NODOC:
429 430 431 |
# File 'lib/protocol_buffers/runtime/message.rb', line 429 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)
279 280 281 |
# File 'lib/protocol_buffers/runtime/message.rb', line 279 def self.parse(io) self.new.parse(io) end |
.repeated(type, name, tag, opts = {}) ⇒ Object
:NODOC:
433 434 435 |
# File 'lib/protocol_buffers/runtime/message.rb', line 433 def self.repeated(type, name, tag, opts = {}) # :NODOC: define_field(:repeated, type, name, tag, opts) end |
.required(type, name, tag, opts = {}) ⇒ Object
:NODOC:
424 425 426 427 |
# File 'lib/protocol_buffers/runtime/message.rb', line 424 def self.required(type, name, tag, opts = {}) # :NODOC: define_field(:required, type, name, tag, opts) @has_required_field = true end |
.valid?(message, raise_exception = false) ⇒ Boolean
454 455 456 457 458 459 460 461 462 463 464 465 |
# File 'lib/protocol_buffers/runtime/message.rb', line 454 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
471 472 473 |
# File 'lib/protocol_buffers/runtime/message.rb', line 471 def self.validate!() valid?(, true) end |
Instance Method Details
#==(obj) ⇒ Object
Comparison by class and field values.
314 315 316 317 318 319 320 |
# File 'lib/protocol_buffers/runtime/message.rb', line 314 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
306 307 308 309 310 311 |
# File 'lib/protocol_buffers/runtime/message.rb', line 306 def attributes=(hash = {}) hash.each do |name, value| self.send("#{name}=", value) end self end |
#clear! ⇒ Object
Reset all fields to the default value.
323 324 325 |
# File 'lib/protocol_buffers/runtime/message.rb', line 323 def clear! fields.each { |tag, field| self.__send__("#{field.name}=", nil) } end |
#default_changed(tag) ⇒ Object
442 443 444 445 446 447 448 |
# File 'lib/protocol_buffers/runtime/message.rb', line 442 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.
328 329 330 331 332 333 334 335 |
# File 'lib/protocol_buffers/runtime/message.rb', line 328 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
481 482 483 484 |
# File 'lib/protocol_buffers/runtime/message.rb', line 481 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 }
347 348 349 |
# File 'lib/protocol_buffers/runtime/message.rb', line 347 def fields self.class.fields end |
#inspect ⇒ Object
386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/protocol_buffers/runtime/message.rb', line 386 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:
401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/protocol_buffers/runtime/message.rb', line 401 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.
288 289 290 291 292 293 294 295 |
# File 'lib/protocol_buffers/runtime/message.rb', line 288 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.
299 300 301 |
# File 'lib/protocol_buffers/runtime/message.rb', line 299 def merge_from_string(string) merge_from(self.class.new.parse(string)) end |
#notify_on_change(parent, tag) ⇒ Object
437 438 439 440 |
# File 'lib/protocol_buffers/runtime/message.rb', line 437 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()
269 270 271 272 273 274 275 276 |
# File 'lib/protocol_buffers/runtime/message.rb', line 269 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
475 476 477 478 |
# File 'lib/protocol_buffers/runtime/message.rb', line 475 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
373 374 375 |
# File 'lib/protocol_buffers/runtime/message.rb', line 373 def set_value_for_tag(tag, value) self.__send__("#{fields[tag].name}=", value) end |
#unknown_field_count ⇒ Object
486 487 488 |
# File 'lib/protocol_buffers/runtime/message.rb', line 486 def unknown_field_count (@unknown_fields || []).size end |
#valid? ⇒ Boolean
450 451 452 |
# File 'lib/protocol_buffers/runtime/message.rb', line 450 def valid? self.class.valid?(self) end |
#validate! ⇒ Object
467 468 469 |
# File 'lib/protocol_buffers/runtime/message.rb', line 467 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
369 370 371 |
# File 'lib/protocol_buffers/runtime/message.rb', line 369 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?
382 383 384 |
# File 'lib/protocol_buffers/runtime/message.rb', line 382 def value_for_tag?(tag) @set_fields[tag] || false end |