class EntitySchema::Contracts::Contract

Check data with strict contract, described with Hash-based DSL

Attributes

rules[R]

Public Class Methods

build(*arguments_arr) click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 8
def build(*arguments_arr)
  params      = arguments_arr.to_a
  options     = params.last.is_a?(Hash) ? params.pop : {}
  new(to_params_hash(params).merge(options))
end
new(rules) click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 21
def initialize(rules)
  @rules = rules.dup
  @rules.each_value { |rule| rule.transform_values! { |v| v.nil? ? [nil] : Array(v) } }
  @rules.each(&:freeze).freeze
  freeze
end
to_params_hash(arr) click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 14
def to_params_hash(arr)
  arr.each_with_object({}).with_index do |(value, params), i|
    params["argument #{i + 1}"] = value
  end
end

Public Instance Methods

+(other) click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 28
def +(other)
  args        = other.to_a
  options     = args.last.is_a?(Hash) ? args.pop : {}
  other_rules = to_params_hash(args).merge(options)
  merge(rules.merge(other_rules))
end
call(*params, skip_unknown: false, **options) click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 40
def call(*params, skip_unknown: false, **options) # rubocop:disable Metrics/AbcSize
  keyvalue = to_params_hash(params).merge(options)
  keyvalue.each do |key, value|
    rules.key?(key) || skip_unknown || raise_unknown!(key, value)

    r = rules[key]
    next if r[:eq]&.any?         { |expectation| expectation == value }
    next if r[:type]&.any?       { |type| value.is_a?(type) }
    next if r[:respond_to]&.any? { |meth| value.respond_to?(meth) }
    raise_unexpected_value(r, key, value)
  end
  true
end
merge(other) click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 35
def merge(other)
  other_rules = other.to_h
  self.class.new(rules.merge(other_rules))
end
to_a() click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 58
def to_a
  params, options = to_arguments(rules)
  params << options
end
to_h() click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 54
def to_h
  rules
end

Private Instance Methods

raise_unexpected_value(rules, key, value) click to toggle source

rubocop:disable Metrics/LineLength

# File lib/entity_schema/contracts/contract.rb, line 86
def raise_unexpected_value(rules, key, value)
  msg  = "Unexpected #{key.inspect} value `#{value.inspect}`. \n" \
         '  Expected to:'
  msgs = []
  msgs << "\n    be equal to: #{rules[:eq]}" if rules.key?(:eq)
  msgs << "\n    be one of: #{rules[:type]}" if rules[:type]
  msgs << "\n    respond to one of the methods: #{rules[:respond_to]}" if rules.key?(:respond_to)
  raise TypeError, (msg + msgs * ' OR')
end
raise_unknown!(key, value) click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 80
def raise_unknown!(key, value)
  raise "Unknown option `#{key.inspect} => #{value.inspect}` given." \
        "  Known options: #{rules.keys}"
end
to_arguments(hash) click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 71
def to_arguments(hash)
  arr = []
  hash = hash.dup
  hash.each_key do |k|
    arr << hash.delete(k) if k.is_a?(String) && k.start_with?('argument ')
  end
  [arr, hash]
end
to_params_hash(a) click to toggle source
# File lib/entity_schema/contracts/contract.rb, line 67
def to_params_hash(a)
  self.class.to_params_hash(a)
end