Class: Babl::Utils::Value

Inherits:
Struct
  • Object
show all
Defined in:
lib/babl/utils/value.rb

Overview

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)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.new(*fields) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 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) ⇒ Object

Raises:

  • (::ArgumentError)


46
47
48
49
50
# 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

Instance Method Details

#==(other) ⇒ Object



41
42
43
# File 'lib/babl/utils/value.rb', line 41

def ==(other)
    eql?(other)
end

#hashObject



37
38
39
# File 'lib/babl/utils/value.rb', line 37

def hash
    self._cached_hash ||= super
end