Class: BloodContracts::Core::Tuple

Inherits:
Refined
  • Object
show all
Defined in:
lib/blood_contracts/core/tuple.rb

Overview

Meta refinement type, represents product of several refinement types

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes inherited from Refined

#context, #errors

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Refined

===, and_then, call, #invalid?, match, or_a, #unpack, #valid?

Constructor Details

#initialize(*values, context: {}) ⇒ Tuple

Tuple constructor, builds Tuple from list of data values

Parameters:

  • *values (Array<Object>)

    that we’ll keep inside the Tuple

  • [Hash<Symbol, (Hash)

    a customizable set of options



125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/blood_contracts/core/tuple.rb', line 125

def initialize(*values, context: {}, **)
  @context = context
  @context[:attributes] ||= {}

  additional_context = values.last if values.last.is_a?(Hash)
  additional_context ||= {}

  @values = parse_values_from_context(context.merge(additional_context))
  @values ||= values

  @errors = []
end

Class Attribute Details

.attributesArray<Refined> (readonly)

List of types in the Tuple

Returns:



12
13
14
# File 'lib/blood_contracts/core/tuple.rb', line 12

def attributes
  @attributes
end

.failure_klassContractFailure

Accessor to define alternative to ContractFailure for #failure method to use

Returns:



63
64
65
# File 'lib/blood_contracts/core/tuple.rb', line 63

def failure_klass
  @failure_klass
end

.namesArray<Symbol> (readonly)

Names of attributes

Returns:

  • (Array<Symbol>)


18
19
20
# File 'lib/blood_contracts/core/tuple.rb', line 18

def names
  @names
end

Instance Attribute Details

#valuesArray<Object> (readonly)

List of values in Tuple

Returns:

  • (Array<Object>)


118
119
120
# File 'lib/blood_contracts/core/tuple.rb', line 118

def values
  @values
end

Class Method Details

.attribute(name, type = nil, &block) ⇒ Object

Helper which registers attribute in the Tuple, also defines a reader



43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/blood_contracts/core/tuple.rb', line 43

def attribute(name, type = nil, &block)
  if type.nil?
    type = type_from_block(name, &block)
  else
    raise ArgumentError unless type < Refined
  end

  @attributes << type
  @names << name

  define_method(name) do
    match.context.dig(:attributes, name)
  end
end

.inherited(new_klass) ⇒ Object



64
65
66
67
68
69
70
# File 'lib/blood_contracts/core/tuple.rb', line 64

def inherited(new_klass)
  new_klass.instance_variable_set(:@attributes, [])
  new_klass.instance_variable_set(:@names, [])
  new_klass.instance_variable_set(:@finalized, true)
  new_klass.failure_klass ||= TupleContractFailure
  super
end

.new(*args, **kwargs, &block) ⇒ Object

Metaprogramming around constructor Turns input into Tuple meta-class

rubocop:disable Style/SingleLineMethods

Raises:

  • (ArgumentError)


26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/blood_contracts/core/tuple.rb', line 26

def new(*args, **kwargs, &block)
  args = lookup_hash_args(*args, kwargs)

  return super(*args, **kwargs) if @finalized
  names = args.pop.delete(:names) if args.last.is_a?(Hash)

  raise ArgumentError unless args.all? { |type| type < Refined }
  tuple = Class.new(self) { def inspect; super; end }
  tuple.instance_variable_set(:@attributes, args)
  tuple.instance_variable_set(:@names, names.to_a)
  tuple.instance_variable_set(:@finalized, true)
  tuple.class_eval(&block) if block_given?
  tuple
end

Instance Method Details

#attribute_errorsHash<String, ContractFailure>

Subset of attributes which are invalid

Returns:



191
192
193
# File 'lib/blood_contracts/core/tuple.rb', line 191

def attribute_errors
  {}
end

#attributesHash<String, Refined>

Hash of attributes (name & type pairs)

Returns:



183
184
185
# File 'lib/blood_contracts/core/tuple.rb', line 183

def attributes
  @context[:attributes]
end

#mappedArray<Object>

Turns match into array of unpacked values

Returns:

  • (Array<Object>)


158
159
160
# File 'lib/blood_contracts/core/tuple.rb', line 158

def mapped
  @matches.map(&:unpack)
end

#matchBC::Refined

The type which is the result of data matching process For Tuple it verifies that all the attributes data are valid types

Returns:



143
144
145
146
147
148
149
150
151
152
# File 'lib/blood_contracts/core/tuple.rb', line 143

def match
  @matches = attributes_enumerator.map do |(type, value), index|
    attribute_name = self.class.names[index]
    attributes.store(
      attribute_name, type.match(value, context: @context.dup)
    )
  end
  return if (failures = @matches.select(&:invalid?)).empty?
  failures.unshift(failure).reduce(:merge!)
end

#unpack_hHash<String, ContractFailure> Also known as: to_hash, to_h, unpack_attributes

Unpacked value in form of a hash per attribute

Returns:



172
173
174
# File 'lib/blood_contracts/core/tuple.rb', line 172

def unpack_h
  @unpack_h ||= attributes.transform_values(&:unpack)
end