Module: Protobuf::Message::Fields::ClassMethods

Defined in:
lib/protobuf/message/fields.rb

Instance Method Summary collapse

Instance Method Details

#all_fieldsObject

Field Access Methods



56
57
58
# File 'lib/protobuf/message/fields.rb', line 56

def all_fields
  @all_fields ||= field_store.values.uniq.sort_by(&:tag)
end

#define_field(rule, type_class, fully_qualified_field_name, tag, options) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/protobuf/message/fields.rb', line 99

def define_field(rule, type_class, fully_qualified_field_name, tag, options)
  raise_if_tag_collision(tag, fully_qualified_field_name)
  raise_if_name_collision(fully_qualified_field_name)

  # Determine appropirate accessor for fields depending on name collisions via extensions:

  # Case 1: Base field = "string_field" and no extensions of the same name
  # Result:
  #   message.string_field #=> @values["string_field"]
  #   message[:string_field] #=> @values["string_field"]
  #   message['string_field'] #=> @values["string_field"]

  # Case 2: Base field = "string_field" and extension 1 = ".my_package.string_field", extension N = ".package_N.string_field"...
  # Result:
  #   message.string_field #=> @values["string_field"]
  #   message[:string_field] #=> @values["string_field"]
  #   message['string_field'] #=> @values["string_field"]
  #   message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
  #   message['.my_package.string_field']  #=> @values[".my_package.string_field"]

  # Case 3: No base field, extension 1 = ".my_package.string_field", extension 2 = ".other_package.string_field", extension N...
  # Result:
  #   message.string_field #=> raise NoMethodError (no simple accessor allowed)
  #   message[:string_field] #=> raise NoMethodError (no simple accessor allowed)
  #   message['string_field'] #=> raise NoMethodError (no simple accessor allowed)
  #   message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
  #   message['.my_package.string_field']  #=> @values[".my_package.string_field"]
  #   message[:'.other_package.string_field'] #=> @values[".other_package.string_field"]
  #   message['.other_package.string_field']  #=> @values[".other_package.string_field"]

  # Case 4: No base field, extension = ".my_package.string_field", no other extensions
  # Result:
  #   message.string_field #=> @values[".my_package.string_field"]
  #   message[:string_field] #=> @values[".my_package.string_field"]
  #   message['string_field'] #=> @values[".my_package.string_field"]
  #   message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
  #   message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]

  simple_name =
    if options[:extension]
      base_name = fully_qualified_field_name.to_s.split('.').last.to_sym
      if field_store[base_name]
        # Case 3
        if field_store[base_name].extension?
          remove_existing_accessors(base_name)
        end
        nil
      # Case 4
      else
        base_name
      end
    else
      # Case 1
      fully_qualified_field_name
    end

  field = ::Protobuf::Field.build(self, rule, type_class, fully_qualified_field_name,
                                  tag, simple_name, options)
  field_store[tag] = field
  field_store[fully_qualified_field_name.to_sym] = field
  field_store[fully_qualified_field_name.to_s] = field
  if simple_name && simple_name != fully_qualified_field_name
    field_store[simple_name.to_sym] = field
    field_store[simple_name.to_s] = field
  end
  # defining a new field for the message will cause cached @all_fields, @extension_fields,
  # and @fields to be incorrect; reset them
  @all_fields = @extension_fields = @fields = nil
end

#extension_fieldsObject



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

def extension_fields
  @extension_fields ||= all_fields.select(&:extension?)
end

#extension_rangesObject



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

def extension_ranges
  @extension_ranges ||= []
end

#extension_tag?(tag) ⇒ Boolean

Returns:

  • (Boolean)


68
69
70
# File 'lib/protobuf/message/fields.rb', line 68

def extension_tag?(tag)
  tag.respond_to?(:to_i) && get_extension_field(tag).present?
end

#extensions(range) ⇒ Object

Define an extension range.



49
50
51
# File 'lib/protobuf/message/fields.rb', line 49

def extensions(range)
  extension_ranges << range
end

#field_storeObject



72
73
74
# File 'lib/protobuf/message/fields.rb', line 72

def field_store
  @field_store ||= {}
end

#field_tag?(tag, allow_extension = false) ⇒ Boolean

Returns:

  • (Boolean)


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

def field_tag?(tag, allow_extension = false)
  tag.respond_to?(:to_i) && get_field(tag, allow_extension).present?
end

#fieldsObject



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

def fields
  @fields ||= all_fields.reject(&:extension?)
end

#get_extension_field(name_or_tag) ⇒ Object



84
85
86
87
# File 'lib/protobuf/message/fields.rb', line 84

def get_extension_field(name_or_tag)
  field = field_store[name_or_tag]
  field if field.try(:extension?) { false }
end

#get_field(name_or_tag, allow_extension = false) ⇒ Object



89
90
91
92
93
94
95
96
97
# File 'lib/protobuf/message/fields.rb', line 89

def get_field(name_or_tag, allow_extension = false)
  field = field_store[name_or_tag]

  if field && (allow_extension || !field.extension?)
    field
  else
    nil
  end
end

#inherited(subclass) ⇒ Object



21
22
23
# File 'lib/protobuf/message/fields.rb', line 21

def inherited(subclass)
  inherit_fields!(subclass)
end

#optional(type_class, name, tag, options = {}) ⇒ Object

Define an optional field.



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

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

#raise_if_name_collision(field_name) ⇒ Object



188
189
190
191
192
# File 'lib/protobuf/message/fields.rb', line 188

def raise_if_name_collision(field_name)
  if get_field(field_name, true)
    fail DuplicateFieldNameError, %(Field name #{field_name} has already been used in "#{name}".)
  end
end

#raise_if_tag_collision(tag, field_name) ⇒ Object



182
183
184
185
186
# File 'lib/protobuf/message/fields.rb', line 182

def raise_if_tag_collision(tag, field_name)
  if get_field(tag, true)
    fail TagCollisionError, %(Field number #{tag} has already been used in "#{name}" by field "#{field_name}".)
  end
end

#remove_existing_accessors(accessor) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/protobuf/message/fields.rb', line 169

def remove_existing_accessors(accessor)
  field_store.delete(accessor.to_sym).try(:fully_qualified_name_only!)
  field_store.delete(accessor.to_s)
  ACCESSOR_SUFFIXES.each do |modifier|
    begin
      remove_method("#{accessor}#{modifier}")
    # rubocop: disable Lint/HandleExceptions
    rescue NameError
      # Do not remove the method
    end
  end
end

#repeated(type_class, name, tag, options = {}) ⇒ Object

Define a repeated field.



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

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

#required(type_class, name, tag, options = {}) ⇒ Object

Define a required field.



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

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