Module: ArchSpec::ValueObject

Defined in:
lib/archspec/value_object.rb

Class Method Summary collapse

Class Method Details

.define(*members, &block) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
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
# File 'lib/archspec/value_object.rb', line 5

def self.define(*members, &block)
  klass = Struct.new(*members) do
    members.each { |member| undef_method :"#{member}=" }

    def initialize(*values, **keywords)
      member_names = self.class.members

      if keywords.any?
        raise ArgumentError, 'expected positional arguments or keyword arguments, not both' unless values.empty?

        unknown = keywords.keys - member_names
        raise ArgumentError, "unknown keyword: #{unknown.first.inspect}" if unknown.any?

        missing = member_names - keywords.keys
        raise ArgumentError, "missing keyword: #{missing.first.inspect}" if missing.any?

        values = member_names.map { |member| keywords.fetch(member) }
      elsif values.length != member_names.length
        raise ArgumentError, "wrong number of arguments (given #{values.length}, expected #{member_names.length})"
      end

      super(*values)
      freeze
    end

    def with(**changes)
      unknown = changes.keys - self.class.members
      raise ArgumentError, "unknown keyword: #{unknown.first.inspect}" if unknown.any?

      self.class.new(**to_h.merge(changes))
    end
  end

  klass.class_eval(&block) if block
  klass
end