class BloodContracts::Core::Refined

Base class for refinement type validations

Attributes

failure_klass[RW]

Accessor to define alternative to ContractFailure for failure method to use

@return [ContractFailure]

context[RW]

Matching context, contains extra debugging and output data

@return [Hash<Symbol, Object>]

errors[R]

List of errors per type

@return [Array<Hash<Refined, String>>]

Public Class Methods

===(object) click to toggle source

Override of case equality operator, to handle Tuple correctly

Calls superclass method
# File lib/blood_contracts/core/refined.rb, line 43
def ===(object)
  return object.attributes.values.any?(self) if object.is_a?(Tuple)
  super
end
>(other_type)
Alias for: and_then
and_then(other_type) click to toggle source

Compose types in a Pipe check Pipe passes data from type to type sequentially

@return [BC::Pipe]

# File lib/blood_contracts/core/refined.rb, line 22
def and_then(other_type)
  BC::Pipe.new(self, other_type)
end
Also aliased as: >
call(*args, **kwargs, &block)
Alias for: match
inherited(new_klass) click to toggle source
# File lib/blood_contracts/core/refined.rb, line 54
def inherited(new_klass)
  new_klass.failure_klass ||= ContractFailure
end
match(*args, **kwargs, &block) click to toggle source

Validate data over refinement type conditions Result is ALWAYS a Refined, but in cases when validation failed, we return ContractFailure ancestor or ContractFailure itself (which is Refined anyway)

@return [Refined]

# File lib/blood_contracts/core/refined.rb, line 34
def match(*args, **kwargs, &block)
  instance = new(*args, **kwargs)
  match = instance.match(&block) || instance
  instance.instance_variable_set(:@match, match)
  match
end
Also aliased as: call
new(value, context: {}, **) click to toggle source

Refinement type constructor

@param [Object] value that Refined holds and should match @option [Hash<Symbol, Object>] context to share between types

# File lib/blood_contracts/core/refined.rb, line 76
def initialize(value, context: {}, **)
  @errors = []
  @context = context
  @value = value
end
or_a(other_type) click to toggle source

Compose types in a Sum check Sum passes data from type to type in parallel, only one type have to match

@return [BC::Sum]

# File lib/blood_contracts/core/refined.rb, line 11
def or_a(other_type)
  BC::Sum.new(self, other_type)
end
Also aliased as: or_an, |
or_an(other_type)
Alias for: or_a
|(other_type)
Alias for: or_a

Public Instance Methods

call()
Alias for: match
invalid?() click to toggle source

Checks whether the data matches the expectations or not (just negation of valid?)

@return [Boolean]

# File lib/blood_contracts/core/refined.rb, line 109
def invalid?
  !valid?
end
unpack() click to toggle source

Unpack the original value from the refinement type

@return [Object]

# File lib/blood_contracts/core/refined.rb, line 117
def unpack
  @unpack ||= mapped
end
valid?() click to toggle source

Checks whether the data matches the expectations or not

@return [Boolean]

# File lib/blood_contracts/core/refined.rb, line 100
def valid?
  @match.errors.empty?
end

Protected Instance Methods

failure(error = nil, errors: @errors, **kwargs) click to toggle source

Helper to build a ContractFailure with shared context

@return [ContractFailure]

# File lib/blood_contracts/core/refined.rb, line 127
def failure(error = nil, errors: @errors, **kwargs)
  error ||= kwargs unless kwargs.empty?
  errors << error if error
  self.class.failure_klass.new(
    { self.class => errors }, context: @context
  )
end
mapped() click to toggle source

Transform the value before unpacking

# File lib/blood_contracts/core/refined.rb, line 92
          def mapped
  value
end
match() click to toggle source

The type which is the result of data matching process

@return [BC::Refined]

# File lib/blood_contracts/core/refined.rb, line 86
          def match
  raise NotImplementedError
end
Also aliased as: call
refine_value(value) click to toggle source

Turn data into refinement type if it is not already

@return [Object]

# File lib/blood_contracts/core/refined.rb, line 156
def refine_value(value)
  refined?(value) ? value.match : Anything.new(value)
end
refined?(object) click to toggle source
# File lib/blood_contracts/core/refined.rb, line 142
def refined?(object)
  object.class < BloodContracts::Core::Refined
end
share_context_with(match) { |context| ... } click to toggle source

FIXME: do we need it?

# File lib/blood_contracts/core/refined.rb, line 147
def share_context_with(match)
  match.context = @context.merge!(match.context)
  yield(match.context)
end
unpack_refined(value) click to toggle source

Turn value into raw data if it is refined

@return [Object]

# File lib/blood_contracts/core/refined.rb, line 164
def unpack_refined(value)
  refined?(value) ? value.unpack : value
end
value() click to toggle source

Helper to turn value into raw data

@return [Object]

# File lib/blood_contracts/core/refined.rb, line 138
def value
  unpack_refined(@value)
end