Class: SumsUp::Core::Variant

Inherits:
Object
  • Object
show all
Defined in:
lib/sums_up/core/variant.rb

Overview

Represents a variant of a sumtype. Use build_variant_class to generate a new subclass for a given variant.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*values) ⇒ Variant

Returns a new instance of Variant.



42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/sums_up/core/variant.rb', line 42

def initialize(*values)
  given = values.length
  expected = self.class::MEMBERS.length

  if given != expected
    raise(
      ArgumentError,
      "wrong number of arguments (given #{given}, expected #{expected})"
    )
  end

  @values = values
end

Class Method Details

.accessors_module(members) ⇒ Object



22
23
24
25
26
27
28
29
30
# File 'lib/sums_up/core/variant.rb', line 22

def self.accessors_module(members)
  Module.new do
    members.each_with_index do |member, idx|
      define_method(member) { @values[idx] }

      define_method(:"#{member}=") { |val| @values[idx] = val }
    end
  end
end

.build_variant_class(name, other_names, members, matcher_class) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/sums_up/core/variant.rb', line 8

def self.build_variant_class(name, other_names, members, matcher_class)
  Class.new(self) do
    const_set(:VARIANT, name)
    const_set(:MEMBERS, members.freeze)

    const_set(:Accessors, accessors_module(members))
    const_set(:Matcher, matcher_class)
    const_set(:Predicates, predicates_module(name, other_names))

    include(const_get(:Accessors))
    include(const_get(:Predicates))
  end
end

.predicates_module(correct_name, incorrect_names) ⇒ Object



32
33
34
35
36
37
38
39
40
# File 'lib/sums_up/core/variant.rb', line 32

def self.predicates_module(correct_name, incorrect_names)
  Module.new do
    define_method(:"#{correct_name}?", &Functions.const(true))

    incorrect_names.each do |incorrect_name|
      define_method(:"#{incorrect_name}?", &Functions.const(false))
    end
  end
end

Instance Method Details

#==(other) ⇒ Object



121
122
123
124
# File 'lib/sums_up/core/variant.rb', line 121

def ==(other)
  other.is_a?(self.class) &&
    (other.to_a(dup: false) == @values)
end

#[](key) ⇒ Object



56
57
58
59
60
# File 'lib/sums_up/core/variant.rb', line 56

def [](key)
  idx = index_for_key(key)

  @values[idx]
end

#[]=(key, val) ⇒ Object



62
63
64
65
66
# File 'lib/sums_up/core/variant.rb', line 62

def []=(key, val)
  idx = index_for_key(key)

  @values[idx] = val
end

#attributesObject



90
91
92
# File 'lib/sums_up/core/variant.rb', line 90

def attributes
  self.class::MEMBERS.zip(@values).to_h
end

#inspectObject Also known as: to_s



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/sums_up/core/variant.rb', line 102

def inspect
  # If a sum type is defined but not assigned to a constant, Class.name
  # name will return nil in Ruby 2.
  variant = self.class.name || self.class::VARIANT

  attrs = self.class::MEMBERS
    .zip(@values)
    .map { |member, value| "#{member}=#{value.inspect}" }
    .join(", ")

  if attrs.empty?
    "#<variant #{variant}>"
  else
    "#<variant #{variant} #{attrs}>"
  end
end

#match(**kwargs) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
# File 'lib/sums_up/core/variant.rb', line 68

def match(**kwargs)
  matcher = self.class::Matcher.new(self)

  if block_given?
    yield(matcher)
  else
    matcher._match_hash(kwargs)
  end

  matcher._fetch_result
end

#members(dup: true) ⇒ Object Also known as: to_a



80
81
82
83
84
85
86
# File 'lib/sums_up/core/variant.rb', line 80

def members(dup: true)
  if dup
    @values.dup
  else
    @values
  end
end

#to_h(include_root: true) ⇒ Object



94
95
96
97
98
99
100
# File 'lib/sums_up/core/variant.rb', line 94

def to_h(include_root: true)
  if include_root
    {self.class::VARIANT => attributes}
  else
    attributes
  end
end