Class: Struct

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/pure-struct.rb

Overview

Pure Ruby re-implementation of Struct to ensure cross-Ruby functionality where needed (e.g. Opal)

Struct class object instances store members in @members Array and member values in @member_values Hash

API perfectly matches that of Native Ruby built-in Struct.

Native Ruby built-in Struct implementation is aliased as NativeStruct

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.__new__Object



37
# File 'lib/pure-struct.rb', line 37

alias __new__ new

.new(class_name_or_attribute, *attributes, keyword_init: false) ⇒ Object



40
41
42
43
44
45
46
47
# File 'lib/pure-struct.rb', line 40

def new(class_name_or_attribute, *attributes, keyword_init: false)
  raise 'Arguments cannot be nil' if ARG_VALIDATION[class_name_or_attribute, *attributes]
  class_name = CLASS_NAME_EXTRACTION[class_name_or_attribute]
  attributes.unshift(class_name_or_attribute) if class_name.nil?
  attributes = attributes.map(&:to_sym)
  struct_class = Class.new(self, &CLASS_DEFINITION_FOR_ATTRIBUTES[attributes, keyword_init])
  class_name.nil? ? struct_class : const_set(class_name, struct_class)
end

Instance Method Details

#==(other) ⇒ Object



189
190
191
192
193
# File 'lib/pure-struct.rb', line 189

def ==(other)
  other = coerce(other).first if respond_to?(:coerce, true)
  other.kind_of?(self.class) &&
    @members.all? { |key| (self[key].equal?(self) && other[key].equal?(self)) || self[key] == other[key] }
end

#[](attribute) ⇒ Object

Raises:

  • (NameError)


120
121
122
123
124
# File 'lib/pure-struct.rb', line 120

def [](attribute)
  normalized_attribute = attribute.to_sym
  raise NameError, "no member #{attribute} in struct" unless @members.include?(normalized_attribute)
  @member_values[normalized_attribute]
end

#[]=(attribute, value) ⇒ Object

Raises:

  • (NameError)


114
115
116
117
118
# File 'lib/pure-struct.rb', line 114

def []=(attribute, value)
  normalized_attribute = attribute.to_sym
  raise NameError, "no member #{attribute} in struct" unless @members.include?(normalized_attribute)
  @member_values[normalized_attribute] = value
end

#dig(*args) ⇒ Object



175
176
177
# File 'lib/pure-struct.rb', line 175

def dig(*args)
  @member_values.dig(*args)
end

#each(&block) ⇒ Object

Iterates through each value



127
128
129
# File 'lib/pure-struct.rb', line 127

def each(&block)
  to_a.each(&block)
end

#each_pair(&block) ⇒ Object

Iterates through each member value pair



132
133
134
# File 'lib/pure-struct.rb', line 132

def each_pair(&block)
  @member_values.each_pair(&block)
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


184
185
186
187
# File 'lib/pure-struct.rb', line 184

def eql?(other)
  instance_of?(other.class) &&
    @members.all? { |key| (self[key].equal?(self) && other[key].equal?(self)) || self[key].eql?(other[key]) }
end

#hashObject

Return compound hash value consisting of Struct class hash and all indexed value hashes

Opal doesn’t implement hash as Integer everywhere, returning strings as themselves, so this returns a String in Opal as a safe common denominator for all object types.



199
200
201
202
203
204
205
206
207
208
# File 'lib/pure-struct.rb', line 199

def hash
  return __hash__opal__ if RUBY_ENGINE == 'opal'
  class_hash = self.class.hash
  indexed_values = to_a.each_with_index
  value_hashes = indexed_values.map do |value, i|
    value_hash = value.equal?(self) ? class_hash : value.hash
    i+1 * value_hash
  end
  class_hash + value_hashes.sum
end

#membersObject

Returns member symbols (strings in Opal) representing Struct attribute names



110
111
112
# File 'lib/pure-struct.rb', line 110

def members
  (@members ||= self.class.class_variable_get(:@@attributes)).clone
end

#select(&block) ⇒ Object

Selects values with block (only value is passed in as block arg)



180
181
182
# File 'lib/pure-struct.rb', line 180

def select(&block)
  to_a.select(&block)
end

#sizeObject Also known as: length



170
171
172
# File 'lib/pure-struct.rb', line 170

def size
  @members.size
end

#to_aObject

Returns values Array (no member keys)



142
143
144
# File 'lib/pure-struct.rb', line 142

def to_a
  @member_values.values
end

#to_hObject

Returns member values Hash (includes member keys)



137
138
139
# File 'lib/pure-struct.rb', line 137

def to_h
  @member_values.clone
end

#to_sObject Also known as: inspect

Prints Struct member values including class name if set

#inspect does the same thing

__inspect__ aliases the original Object inspect implementation



155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/pure-struct.rb', line 155

def to_s
  member_values_string = @member_values.map do |member, value|
    if value.equal?(self)
      value_class_string = self.class.send(:__inspect__).split.first
      value_string = "#<struct #{value_class_string}:...>"
    else
      value_string = value.inspect
    end
    "#{member}=#{value_string}"
  end.join(', ')
  class_name_string = "#{self.class.name} " unless self.class.name.nil?
  "#<struct #{class_name_string}#{member_values_string}>"
end