Class: Protobuf::Message

Inherits:
Object
  • Object
show all
Extended by:
Protoable
Defined in:
lib/protobuf/message/message.rb

Defined Under Namespace

Classes: ExtensionFields

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Protoable

defined_filenames, defined_in, proto_contents, proto_filenames, retrieve_header

Constructor Details

#initialize(values = {}) ⇒ Message

Returns a new instance of Message.



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/protobuf/message/message.rb', line 119

def initialize(values={})
  @values = {}

  self.class.fields.each do |tag, field|
    unless field.ready?
      field = field.setup
      self.class.class_eval {@fields[tag] = field}
    end
    if field.repeated?
      @values[field.name] = Field::FieldArray.new(field)
    end
  end

  # TODO
  self.class.extension_fields.each do |tag, field|
    unless field.ready?
      field = field.setup
      self.class.class_eval {@extension_fields[tag] = field}
    end
    if field.repeated?
      @values[field.name] = Field::FieldArray.new(field)
    end
  end

  values.each {|tag, val| self[tag] = val}
end

Class Method Details

.define_field(rule, type, fname, tag, options) ⇒ Object

Define a field. Don't use this method directly.



52
53
54
55
56
57
58
# File 'lib/protobuf/message/message.rb', line 52

def define_field(rule, type, fname, tag, options)
  field_hash = options[:extension] ? extension_fields : fields
  if field_hash.keys.include?(tag)
    raise TagCollisionError, %!{Field number #{tag} has already been used in "#{self.name}" by field "#{fname}".!
  end
  field_hash[tag] = Field.build(self, rule, type, fname, tag, options)
end

.descriptorObject



114
115
116
# File 'lib/protobuf/message/message.rb', line 114

def descriptor
  @descriptor ||= Descriptor::Descriptor.new(self)
end

.extension_fieldsObject

An extension field object.



70
71
72
# File 'lib/protobuf/message/message.rb', line 70

def extension_fields
  @extension_fields ||= ExtensionFields.new
end

.extension_tag?(tag) ⇒ Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/protobuf/message/message.rb', line 60

def extension_tag?(tag)
  extension_fields.include_tag?(tag)
end

.extensions(range) ⇒ Object

Reserve field numbers for extensions. Don't use this method directly.



32
33
34
# File 'lib/protobuf/message/message.rb', line 32

def extensions(range)
  @extension_fields = ExtensionFields.new(range)
end

.fieldsObject

A collection of field object.



65
66
67
# File 'lib/protobuf/message/message.rb', line 65

def fields
  @fields ||= {}
end

.get_ext_field(tag_or_name) ⇒ Object

TODO merge to get_field



106
107
108
109
110
111
112
# File 'lib/protobuf/message/message.rb', line 106

def get_ext_field(tag_or_name)
  case tag_or_name
  when Integer        then get_ext_field_by_tag(tag_or_name)
  when String, Symbol then get_ext_field_by_name(tag_or_name)
  else                     raise TypeError, tag_or_name.class
  end
end

.get_ext_field_by_name(name) ⇒ Object

TODO merge to get_field_by_name



95
96
97
98
# File 'lib/protobuf/message/message.rb', line 95

def get_ext_field_by_name(name)
  name = name.to_sym
  extension_fields.values.find {|field| field.name == name}
end

.get_ext_field_by_tag(tag) ⇒ Object

TODO merge to get_field_by_tag



101
102
103
# File 'lib/protobuf/message/message.rb', line 101

def get_ext_field_by_tag(tag)
  extension_fields[tag]
end

.get_field(tag_or_name) ⇒ Object

Find a field object by +tag_or_name+.



86
87
88
89
90
91
92
# File 'lib/protobuf/message/message.rb', line 86

def get_field(tag_or_name)
  case tag_or_name
  when Integer        then get_field_by_tag(tag_or_name)
  when String, Symbol then get_field_by_name(tag_or_name)
  else                     raise TypeError, tag_or_name.class
  end
end

.get_field_by_name(name) ⇒ Object

Find a field object by +name+.



75
76
77
78
# File 'lib/protobuf/message/message.rb', line 75

def get_field_by_name(name)
  name = name.to_sym
  fields.values.find {|field| field.name == name}
end

.get_field_by_tag(tag) ⇒ Object

Find a field object by +tag+ number.



81
82
83
# File 'lib/protobuf/message/message.rb', line 81

def get_field_by_tag(tag)
  fields[tag]
end

.optional(type, name, tag, options = {}) ⇒ Object

Define a optional field. Don't use this method directly.



42
43
44
# File 'lib/protobuf/message/message.rb', line 42

def optional(type, name, tag, options={})
  define_field(:optional, type, name, tag, options)
end

.repeated(type, name, tag, options = {}) ⇒ Object

Define a repeated field. Don't use this method directly.



47
48
49
# File 'lib/protobuf/message/message.rb', line 47

def repeated(type, name, tag, options={})
  define_field(:repeated, type, name, tag, options)
end

.required(type, name, tag, options = {}) ⇒ Object

Define a required field. Don't use this method directly.



37
38
39
# File 'lib/protobuf/message/message.rb', line 37

def required(type, name, tag, options={})
  define_field(:required, type, name, tag, options)
end

Instance Method Details

#==(obj) ⇒ Object



157
158
159
160
161
162
163
# File 'lib/protobuf/message/message.rb', line 157

def ==(obj)
  return false unless obj.is_a?(self.class)
  each_field do |field, value|
    return false unless value == obj.__send__(field.name)
  end
  true
end

#[](tag_or_name) ⇒ Object



300
301
302
303
304
305
306
# File 'lib/protobuf/message/message.rb', line 300

def [](tag_or_name)
  if field = get_field(tag_or_name) || get_ext_field(tag_or_name)
    __send__(field.name)
  else
    raise NoMethodError, "No such field: #{tag_or_name.inspect}"
  end
end

#[]=(tag_or_name, value) ⇒ Object



308
309
310
311
312
313
314
# File 'lib/protobuf/message/message.rb', line 308

def []=(tag_or_name, value)
  if field = get_field(tag_or_name) || get_ext_field(tag_or_name)
    __send__("#{field.name}=", value)
  else
    raise NoMethodError, "No such field: #{tag_or_name.inspect}"
  end
end

#clear!Object



165
166
167
168
169
170
171
172
173
174
175
# File 'lib/protobuf/message/message.rb', line 165

def clear!
  @values.delete_if do |_, value|
    if value.is_a?(Field::FieldArray)
      value.clear
      false
    else
      true
    end
  end
  self
end

#cloneObject



181
182
183
# File 'lib/protobuf/message/message.rb', line 181

def clone
  copy_to(super, :clone)
end

#dupObject



177
178
179
# File 'lib/protobuf/message/message.rb', line 177

def dup
  copy_to(super, :dup)
end

#each_fieldObject

Iterate over a field collection. message.each_field do |field_object, value| # do something end



357
358
359
360
361
362
# File 'lib/protobuf/message/message.rb', line 357

def each_field
  fields.merge(extension_fields).sort_by {|tag, _| tag}.each do |_, field|
    value = __send__(field.name)
    yield(field, value)
  end
end

#extension_fieldsObject

Returns extension fields. See Message#fields method.



337
338
339
# File 'lib/protobuf/message/message.rb', line 337

def extension_fields
  self.class.extension_fields
end

#fieldsObject

Returns a hash; which key is a tag number, and value is a field object.



317
318
319
# File 'lib/protobuf/message/message.rb', line 317

def fields
  self.class.fields
end

#get_ext_field(tag_or_name) ⇒ Object

:nodoc:



349
350
351
# File 'lib/protobuf/message/message.rb', line 349

def get_ext_field(tag_or_name) # :nodoc:
  self.class.get_ext_field(tag_or_name)
end

#get_ext_field_by_name(name) ⇒ Object

:nodoc:



341
342
343
# File 'lib/protobuf/message/message.rb', line 341

def get_ext_field_by_name(name) # :nodoc:
  self.class.get_ext_field_by_name(name)
end

#get_ext_field_by_tag(tag) ⇒ Object

:nodoc:



345
346
347
# File 'lib/protobuf/message/message.rb', line 345

def get_ext_field_by_tag(tag) # :nodoc:
  self.class.get_ext_field_by_tag(tag)
end

#get_field(tag_or_name) ⇒ Object

Returns field object or +nil+.



332
333
334
# File 'lib/protobuf/message/message.rb', line 332

def get_field(tag_or_name)
  self.class.get_field(tag_or_name)
end

#get_field_by_name(name) ⇒ Object

Returns field object or +nil+.



322
323
324
# File 'lib/protobuf/message/message.rb', line 322

def get_field_by_name(name)
  self.class.get_field_by_name(name)
end

#get_field_by_tag(tag) ⇒ Object

Returns field object or +nil+.



327
328
329
# File 'lib/protobuf/message/message.rb', line 327

def get_field_by_tag(tag)
  self.class.get_field_by_tag(tag)
end

#has_field?(tag_or_name) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


151
152
153
154
155
# File 'lib/protobuf/message/message.rb', line 151

def has_field?(tag_or_name)
  field = get_field(tag_or_name) || get_ext_field(tag_or_name)
  raise ArgumentError, "unknown field: #{tag_or_name.inspect}" unless field
  @values.has_key?(field.name)
end

#initialized?Boolean

Returns:

  • (Boolean)


146
147
148
149
# File 'lib/protobuf/message/message.rb', line 146

def initialized?
  fields.all? {|tag, field| field.initialized?(self) } && \
    extension_fields.all? {|tag, field| field.initialized?(self) }
end

#inspect(indent = 0) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/protobuf/message/message.rb', line 205

def inspect(indent=0)
  result = []
  i = '  ' * indent
  field_value_to_string = lambda {|field, value|
    result << \
      if field.optional? && ! has_field?(field.name)
        ''
      else
        case field
        when Field::MessageField then
          if value.nil?
            "#{i}#{field.name} {}\n"
          else
            "#{i}#{field.name} {\n#{value.inspect(indent + 1)}#{i}}\n"
          end
        when Field::EnumField then
          if value.is_a?(EnumValue)
            "#{i}#{field.name}: #{value.name}\n"
          else
            "#{i}#{field.name}: #{field.type.name_by_value(value)}\n"
          end
        else
          "#{i}#{field.name}: #{value.inspect}\n"
        end
      end
  }
  each_field do |field, value|
    if field.repeated?
      value.each do |v|
        field_value_to_string.call(field, v)
      end
    else
      field_value_to_string.call(field, value)
    end
  end
  result.join
end

#merge_field(tag, value) ⇒ Object



295
296
297
298
# File 'lib/protobuf/message/message.rb', line 295

def merge_field(tag, value)
  #get_field_by_tag(tag).merge self, bytes #TODO
  (get_field_by_tag(tag) || get_ext_field_by_tag(tag)).merge(self, value)
end

#merge_from(message) ⇒ Object



284
285
286
287
288
# File 'lib/protobuf/message/message.rb', line 284

def merge_from(message)
  # TODO
  fields.each {|tag, field| merge_field(tag, message.__send__(field.name))}
  extension_fields.each {|tag, field| merge_field(tag, message.__send__(field.name))}
end

#parse_from(stream) ⇒ Object



257
258
259
# File 'lib/protobuf/message/message.rb', line 257

def parse_from(stream)
  Decoder.decode(stream, self)
end

#parse_from_file(filename) ⇒ Object



247
248
249
250
251
252
253
254
255
# File 'lib/protobuf/message/message.rb', line 247

def parse_from_file(filename)
  if filename.is_a?(File)
    parse_from(filename)
  else
    File.open(filename, 'rb') do |f|
      parse_from(f)
    end
  end
end

#parse_from_string(string) ⇒ Object



243
244
245
# File 'lib/protobuf/message/message.rb', line 243

def parse_from_string(string)
  parse_from(StringIO.new(string))
end

#serialize_to(stream) ⇒ Object



280
281
282
# File 'lib/protobuf/message/message.rb', line 280

def serialize_to(stream)
  Encoder.encode(stream, self)
end

#serialize_to_file(filename) ⇒ Object



270
271
272
273
274
275
276
277
278
# File 'lib/protobuf/message/message.rb', line 270

def serialize_to_file(filename)
  if filename.is_a?(File)
    serialize_to(filename)
  else
    File.open(filename, 'wb') do |f|
      serialize_to(f)
    end
  end
end

#serialize_to_string(string = '') ⇒ Object Also known as: to_s



261
262
263
264
265
266
267
# File 'lib/protobuf/message/message.rb', line 261

def serialize_to_string(string='')
  io = StringIO.new(string)
  serialize_to(io)
  result = io.string
  result.force_encoding('ASCII-8BIT') if result.respond_to?(:force_encoding)
  result
end

#set_field(tag, bytes) ⇒ Object



290
291
292
293
# File 'lib/protobuf/message/message.rb', line 290

def set_field(tag, bytes)
  field = (get_field_by_tag(tag) || get_ext_field_by_tag(tag))
  field.set(self, bytes) if field
end

#to_hashObject



364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
# File 'lib/protobuf/message/message.rb', line 364

def to_hash
  result = {}
  build_value = lambda {|field, value|
    if !field.optional? || (field.optional? && has_field?(field.name))
      case field
      when Field::MessageField then
        value.to_hash
      when Field::EnumField then
        if value.is_a?(EnumValue)
          value.to_i
        elsif value.is_a?(Symbol)
          field.type[value].to_i
        else
          value
        end
      else
        value
      end
    end
  }
  each_field do |field, value|
    if field.repeated?
      result[field.name] = value.map do |v|
        build_value.call(field, v)
      end
    else
      result[field.name] = build_value.call(field, value)
    end
  end
  result
end

#to_jsonObject



396
397
398
# File 'lib/protobuf/message/message.rb', line 396

def to_json
  to_hash.to_json
end