Class: Protobuf::Message

Inherits:
Object
  • Object
show all
Defined in:
lib/extensions/protobuf/message.rb

Defined Under Namespace

Modules: EncodingType

Constant Summary collapse

@@encoding =

static variable to define the specific encoding to be used. By default, use the primitive encoding type (BINARY)

Protobuf::Message::EncodingType::BINARY

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.encodingObject

encoding getter



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

def self.encoding
  @@encoding
end

.encoding=(encoding) ⇒ Object

encoding setter



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

def self.encoding=(encoding)
  @@encoding = encoding
end

.parse_indexed_to_hash(data, klass) ⇒ Object

This method parses a INDEXED encoded message to a hash using klass message as model. We need to know the specific klass to decode to differenciate between vectors and message fields



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/extensions/protobuf/message.rb', line 211

def self.parse_indexed_to_hash(data, klass)
  values = {}
  index = data.shift
  index.each_codepoint { |tag|
    tag = tag-48
    field = klass.get_field_by_tag(tag)
    val = data.shift

    if val.is_a?(Array) && field.is_a?(Protobuf::Field::MessageField)
      if field.repeated?
        val.map! { |v|
          v = self.parse_indexed_to_hash(v, field.type)
        }
      else
        val = self.parse_indexed_to_hash(val, field.type)
      end
    end
    values[tag.to_s] = val
  }
  values
end

.serialize_hash_to_indexed(value) ⇒ Object

This class method serializes a Hash



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/extensions/protobuf/message.rb', line 138

def self.serialize_hash_to_indexed(value)
  !value.is_a?(Hash) and raise ArgumentError, "value must be a hash"
  # index value
  index = ""
  index.respond_to?(:force_encoding) and index.force_encoding("UTF-8") # 1.9.2
  # field values
  result = []
  value.each_pair { |key, value|
    index << key.to_i+48 # ASCII integer. 1 => 49, ...
    # recursive call if value is a Hash
    if value.is_a?(Hash)
      value = self.class.serialize_hash_to_indexed(value)
      # array => serializes each element
    elsif value.is_a?(Array)
      value.map! { |val|
        if val.is_a?(Hash)
          serialize_hash_to_indexed(val)
        else
          val
        end
      }
    end
    # insert encoded value in Array
    result.push value
  }
  # include index as first element
  result.unshift(index)
end

Instance Method Details

#parse_from_indexed(data) ⇒ Object

This method parses a INDEXED encoded message to a hash using self.class message as model.



235
236
237
238
239
240
# File 'lib/extensions/protobuf/message.rb', line 235

def parse_from_indexed(data)
  # decode if data is JSON
  data.is_a?(String) and data = ActiveSupport::JSON.decode(data)
  values = self.class.parse_indexed_to_hash(data, self)
  parse_from_json(values)
end

#parse_from_json(data, decoding_key = :tag) ⇒ Object

This method parses a JSON encoded message to the self.class object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/extensions/protobuf/message.rb', line 168

def parse_from_json(data, decoding_key = :tag)
  # decode if data is JSON
  data.is_a?(String) and data = ActiveSupport::JSON.decode(data)

  # per each hash element:
  data.each_pair { |key, value|
    key = decoding_key.eql?(:tag) ? key.to_i : key.to_s

    #  get the field object using the key (field tag)
    #field = self.get_field_by_tag(key.to_i)
    field = self.send("get_field_by_#{decoding_key}".to_sym, key)

    if field.nil?
      # ignore unknown field
    elsif field.repeated?
      # create the element
      array = self.__send__(field.name)
      value.each { |val|
      # if value is a complex field, create the object and parse the content
        if field.is_a?(Protobuf::Field::MessageField)
          instance = field.type.new
          val = instance.parse_from_json(val, decoding_key)
        end
        # include each element in the parent element field
        array.push(val)
      }
    else
      # if value is a complex field, create the object and parse the content
      if field.is_a?(Protobuf::Field::MessageField)
        instance = field.type.new
        value = instance.parse_from_json(value, decoding_key)
      end
      # set the message field
      self.__send__("#{field.name}=", value)
    end
  }
  self
end

#parse_from_string(string) ⇒ Object

This method is used to parse the message from a specific format based on the class variable encoding



247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/extensions/protobuf/message.rb', line 247

def parse_from_string(string)
  case @@encoding
    when EncodingType::BINARY
      parse_from_string_old(string)
    when EncodingType::HASHMAP
      parse_from_json(string, :name)
    when EncodingType::TAGMAP
      parse_from_json(string, :tag)
    when EncodingType::INDEXED
      parse_from_indexed(string)
    else
      raise ArgumentError, "Invalid encoding type"
  end
end

#parse_from_string_oldObject

allow new parsing, not only binary



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

alias :parse_from_string_old :parse_from_string

#serialize_to_hash(encoding_key = :tag) ⇒ Hash

Encode the message to a hash object defined as a collection for key/values where each element has:

  • key: field tag

  • value:

  • if field.is_a? message_field => field.value.serialized_to_hash

  • if field.is_a? enum_field => field.value.value

  • else => field.value

Returns:

  • (Hash)

    a specific Message encoded in an Hash object

Raises:

  • (NotInitializedError)


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/extensions/protobuf/message.rb', line 50

def serialize_to_hash(encoding_key = :tag)
  raise NotInitializedError unless self.initialized?
  # var to store the encoded message fields
  result = {}

  # lambda function that extract the field tag and value
  # it's called recursively if value is a MessageField
  field_value_to_string = lambda { |field, value|
    field_value = \
      if field.optional? && !self.has_field?(field.name)
                              ''
      else
        case field
          when Field::MessageField
            if value.nil?
              nil
            else
              value.serialize_to_hash(encoding_key)
            end
          when Field::EnumField
            if value.is_a?(EnumValue)
              value.value
            else
              value.to_i
            end
          else
            value
        end
      end
    return field.send(encoding_key), field_value
  }

  # per each message field create a new element in result var with
  # key = field.tag and value = field.value
  self.each_field do |field, value|
    # create a vector if field is repeated
    if field.repeated? && !value.empty?
      key_value = []
      key = nil
      value.each do |v|
        key, val = field_value_to_string.call(field, v) # always return the same key
        key_value.push val
      end
      # field is not repeated but is not empty
    elsif !field.repeated?
      key, key_value = field_value_to_string.call(field, value)
      # empty field, discard
    else
      next
    end
    # new element in result Hash
    result[key.to_s] = key_value
  end
  result
end

#serialize_to_indexedObject

This method serializes the message in INDEXED format



132
133
134
135
# File 'lib/extensions/protobuf/message.rb', line 132

def serialize_to_indexed
  data = serialize_to_hash
  self.class.serialize_hash_to_indexed(data).to_json
end

#serialize_to_json(encoding_key = :tag) ⇒ Object

This method serializes the message in JSON format



127
128
129
# File 'lib/extensions/protobuf/message.rb', line 127

def serialize_to_json(encoding_key = :tag)
  serialize_to_hash(encoding_key).to_json
end

#serialize_to_string(string = '') ⇒ Object

This method is used to serialize the message to a specific format based on the class variable encoding



111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/extensions/protobuf/message.rb', line 111

def serialize_to_string(string='')
  case @@encoding
    when EncodingType::BINARY # primitive format
      serialize_to_string_old(string)
    when EncodingType::HASHMAP # JSON format with key = field.name
      serialize_to_json(:name)
    when EncodingType::TAGMAP # JSON format with key = field.tag
      serialize_to_json(:tag)
    when EncodingType::INDEXED # INDEXED format
      serialize_to_indexed
    else
      raise ArgumentError, "Invalid encoding type"
  end
end

#serialize_to_string_oldObject

allow new serialization, not only binary



107
# File 'lib/extensions/protobuf/message.rb', line 107

alias :serialize_to_string_old :serialize_to_string