class Babl::Utils::Value
Construct deeply immutable value objects Similar to Struct, but:
-
Properties are assumed deeply immutable (
hash
is assumed constant & store permanently) -
Constructor requires all arguments
-
#== has the same meaning as eql?
Goals :
-
Create completely immutable value objects
-
Fast comparison between instances (using precomputed hash values)
-
Low overhead (relies on native Ruby Struct)
Public Class Methods
new(*fields)
click to toggle source
Calls superclass method
# File lib/babl/utils/value.rb, line 17 def self.new(*fields) fields = fields.map(&:to_sym) field_aliases = ::Array.new(fields.size) { |i| "v#{i}" } clazz = super(:_cached_hash, *fields) clazz.const_set(:FIELDS, fields) clazz.class_eval <<-RUBY, __FILE__, __LINE__ + 1 def initialize(#{field_aliases.join(',')}) super(#{['nil', field_aliases].join(',')}) hash end RUBY fields.each { |field| clazz.send(:define_method, :"#{field}=") { |*| raise ::RuntimeError, 'Object is immutable' } } clazz end
with(hash = Utils::Hash::EMPTY)
click to toggle source
# File lib/babl/utils/value.rb, line 46 def with(hash = Utils::Hash::EMPTY) raise ::ArgumentError unless ::Hash === hash && (hash.keys - self::FIELDS).empty? new(*self::FIELDS.map { |f| hash.fetch(f) }) end
Private Class Methods
memoize(method_name)
click to toggle source
# File lib/babl/utils/value.rb, line 54 def memoize(method_name) old_name = :"_unmemoized_#{method_name}" alias_method old_name, method_name class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{method_name} return @#{old_name} if defined? @#{old_name} @#{old_name} = #{old_name} end RUBY end
Public Instance Methods
==(other)
click to toggle source
# File lib/babl/utils/value.rb, line 41 def ==(other) eql?(other) end
hash()
click to toggle source
Calls superclass method
# File lib/babl/utils/value.rb, line 37 def hash self._cached_hash ||= super end