class Struct
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
Constants
- ARG_VALIDATION
- CLASS_DEFINITION_FOR_ATTRIBUTES
- CLASS_NAME_EXTRACTION
Public Class Methods
# 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
Public Instance Methods
# 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
# 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
# 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
# File lib/pure-struct.rb, line 175 def dig(*args) @member_values.dig(*args) end
Iterates through each value
# File lib/pure-struct.rb, line 127 def each(&block) to_a.each(&block) end
Iterates through each member value pair
# File lib/pure-struct.rb, line 132 def each_pair(&block) @member_values.each_pair(&block) end
# 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
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.
# 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
Returns member symbols (strings in Opal) representing Struct
attribute names
# File lib/pure-struct.rb, line 110 def members (@members ||= self.class.class_variable_get(:@@attributes)).clone end
Selects values with block (only value is passed in as block arg)
# File lib/pure-struct.rb, line 180 def select(&block) to_a.select(&block) end
# File lib/pure-struct.rb, line 170 def size @members.size end
Returns values Array (no member keys)
# File lib/pure-struct.rb, line 142 def to_a @member_values.values end
Returns member values Hash (includes member keys)
# File lib/pure-struct.rb, line 137 def to_h @member_values.clone end
Prints Struct
member values including class name if set
inspect
does the same thing
__inspect__ aliases the original Object
inspect implementation
# 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
Private Instance Methods
# File lib/pure-struct.rb, line 212 def __hash__opal__ class_hash = self.class.hash indexed_values = to_a.each_with_index class_hash = class_hash.to_s value_hashes = indexed_values.map do |value, i| value_hash_string = value.equal?(self) ? class_hash : value.hash.to_s (i+1).to_s + value_hash_string end class_hash + value_hashes.reduce(:+) end