module BloodContracts::Core::Extractable

Concern that turns your refinement type into a coercer with validation delegated to Tram::Policy

Public Class Methods

included(other_class) click to toggle source

@private

# File lib/blood_contracts/core/extractable.rb, line 6
def self.included(other_class)
  other_class.extend(ClassMethods)
end

Public Instance Methods

mapped() click to toggle source

Turns value into the hash of extracted data

@return [Hash]

# File lib/blood_contracts/core/extractable.rb, line 53
def mapped
  keys = self.class.extractors.keys
  Hash[keys.zip(@context.values_at(*keys))]
end
match() click to toggle source

Turns matching process into 2 steps:

  • extraction of data from the value

  • validation using the policy_klass

@return [Refined]

# File lib/blood_contracts/core/extractable.rb, line 45
def match
  extract!
  policy_failure_match! || self
end

Protected Instance Methods

extract!() click to toggle source

Extracts data from the value

@return [Nothing]

# File lib/blood_contracts/core/extractable.rb, line 62
          def extract!
  self.class.extractors.each do |field, settings|
    next if !context[field].nil? && !context[field].empty?

    method_name, = *settings
    context[field] = send(method_name.to_s)
  end
end
policy_failure_match!() click to toggle source

Validates extracted data using policy_klass

@return [Refined, Nil]

# File lib/blood_contracts/core/extractable.rb, line 75
          def policy_failure_match!
  return unless self.class.policy

  policy_input = context.reduce({}) { |a, (k, v)| a.merge!(k.to_sym => v) }
  policy_instance = self.class.policy[**policy_input]
  return if policy_instance.valid?

  failure(policy_instance.errors)
end