class SumsUp::Core::Variant

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

Public Class Methods

accessors_module(members) click to toggle source
# 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) click to toggle source
# 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
new(*values) click to toggle source
# 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
predicates_module(correct_name, incorrect_names) click to toggle source
# 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

Public Instance Methods

==(other) click to toggle source
# File lib/sums_up/core/variant.rb, line 121
def ==(other)
  other.is_a?(self.class) &&
    (other.to_a(dup: false) == @values)
end
[](key) click to toggle source
# File lib/sums_up/core/variant.rb, line 56
def [](key)
  idx = index_for_key(key)

  @values[idx]
end
[]=(key, val) click to toggle source
# File lib/sums_up/core/variant.rb, line 62
def []=(key, val)
  idx = index_for_key(key)

  @values[idx] = val
end
attributes() click to toggle source
# File lib/sums_up/core/variant.rb, line 90
def attributes
  self.class::MEMBERS.zip(@values).to_h
end
inspect() click to toggle source
# 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
Also aliased as: to_s
match(**kwargs) { |matcher| ... } click to toggle source
# 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) click to toggle source
# File lib/sums_up/core/variant.rb, line 80
def members(dup: true)
  if dup
    @values.dup
  else
    @values
  end
end
Also aliased as: to_a
to_a(dup: true)
Alias for: members
to_h(include_root: true) click to toggle source
# 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
to_s()
Alias for: inspect

Private Instance Methods

index_for_key(key) click to toggle source
# File lib/sums_up/core/variant.rb, line 128
def index_for_key(key)
  idx = self.class::MEMBERS.index(key.to_sym)

  return idx if idx

  raise(NameError, "No member '#{key}' in variant #{self.class::VARIANT}")
end