Class: HashInitializedStruct

Inherits:
Object
  • Object
show all
Defined in:
lib/hash_initialized_struct.rb,
lib/hash_initialized_struct/version.rb

Overview

class Point < HashInitializedStruct(:x, :y); end Or: Point = HashInitializedStruct(:x, :y)

point = Point.new(x: 1, y: 2) point.x # => 1

point2 = Point.new(x: 1, y: 2, nonsense: “foobar”) # => raises ArgumentError

Constant Summary collapse

VERSION =
"1.3.0"

Class Method Summary collapse

Class Method Details

.new(*attrs) ⇒ Object



16
17
18
19
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
# File 'lib/hash_initialized_struct.rb', line 16

def self.new(*attrs)
  symbol_attrs = attrs.map do |a|
    case a
    when Symbol
      a
    else
      a.to_sym.tap do |sym|
        raise TypeError, "Could not coerce #{a.inspect} to symbol" unless sym.kind_of?(Symbol)
      end
    end
  end

  Class.new self do
    const_set :STRUCT_ATTRS, symbol_attrs
    attr_accessor *symbol_attrs

    def self.new(*args, &block)
      self.subclass_new(*args, &block)
    end

    def initialize(attrs)
      attrs    = Hash(attrs)
      provided = attrs.keys
      needed   = needed_keys
      self.raise_on_unrecognised_keys(provided, needed)
      self.raise_on_missing_keys(provided, needed)
      set_attributes(attrs)
    end

    def to_h
      # [k,k,...] => [[k,v], [k,v], ...] => {k => v, k => v, ...}
      Hash[ self.class::STRUCT_ATTRS.map {|key| [key, self.public_send(key)]} ]
    end
    alias :to_hash :to_h

    protected

      def needed_keys
        self.class::STRUCT_ATTRS
      end

      def raise_on_unrecognised_keys(provided, needed)
        (provided - needed).tap do |unknown|
          raise ArgumentError, "Unrecognised keys: #{unknown.map(&:inspect).join(', ')}" unless unknown.empty?
        end
      end

      def raise_on_missing_keys(provided, needed)
        (needed - provided).tap do |missing|
          raise ArgumentError, "Missing keys: #{missing.map(&:inspect).join(', ')}" unless missing.empty?
        end
      end

      def set_attributes(attrs)
        attrs.each do |attr,value|
          instance_variable_set("@#{attr}", value)
        end
      end
  end
end

.subclass_newObject



13
# File 'lib/hash_initialized_struct.rb', line 13

alias :subclass_new :new