Class: Value
- Inherits:
-
Object
- Object
- Value
- Defined in:
- lib/values.rb
Overview
Simple immutable value objects for ruby.
Class Method Summary collapse
-
.new(*fields, &block) ⇒ Class
Create a new value class.
Class Method Details
.new(*fields, &block) ⇒ Class
Create a new value class.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/values.rb', line 20 def self.new(*fields, &block) raise ArgumentError.new('wrong number of arguments (0 for 1+)') if fields.empty? Class.new do attr_reader(:hash, *fields) define_method(:initialize) do |*values| raise ArgumentError.new("wrong number of arguments, #{values.size} for #{fields.size}") if fields.size != values.size fields.zip(values) do |field, value| instance_variable_set(:"@#{field}", value) end @hash = self.class.hash ^ values.hash freeze end const_set :VALUE_ATTRS, fields def self.with(hash) unexpected_keys = hash.keys - self::VALUE_ATTRS if unexpected_keys.any? raise ArgumentError.new("Unexpected hash keys: #{unexpected_keys}") end missing_keys = self::VALUE_ATTRS - hash.keys if missing_keys.any? raise ArgumentError.new("Missing hash keys: #{missing_keys} (got keys #{hash.keys})") end new(*hash.values_at(*self::VALUE_ATTRS)) end def ==(other) eql?(other) end def eql?(other) self.class == other.class && values == other.values end def values self.class::VALUE_ATTRS.map { |field| send(field) } end def inspect attributes = to_a.map { |field, value| "#{field}=#{value.inspect}" }.join(", ") "#<#{self.class.name} #{attributes}>" end def with(hash = {}) return self if hash.empty? self.class.with(to_h.merge(hash)) end def to_h Hash[to_a] end def to_a self.class::VALUE_ATTRS.map { |field| [field, send(field)] } end class_eval &block if block end end |