class Contracts::ArgsValidator

Attributes

args_contracts[RW]
args_validators[RW]
contracts[RW]
klass[RW]
method[RW]
splat_args_contract_index[RW]

Public Class Methods

new(opts) click to toggle source
# File lib/contracts/args_validator.rb, line 4
def initialize(opts)
  @splat_args_contract_index = opts.fetch(:splat_args_contract_index)
  @klass                     = opts.fetch(:klass)
  @method                    = opts.fetch(:method)
  @contracts                 = opts.fetch(:contracts)
  @args_contracts            = opts.fetch(:args_contracts)
  @args_validators           = opts.fetch(:args_validators)
end

Public Instance Methods

validate_args_before_splat!(args) click to toggle source

Loop forward validating the arguments up to the splat (if there is one) may change the `args` param

# File lib/contracts/args_validator.rb, line 15
def validate_args_before_splat!(args)
  (splat_args_contract_index || args.size).times do |i|
    validate!(args, i)
  end
end
validate_splat_args_and_after!(args) click to toggle source
possibilities
  • splat is last argument, like: def hello(a, b, *args)

  • splat is not last argument, like: def hello(*args, n)

# File lib/contracts/args_validator.rb, line 24
def validate_splat_args_and_after!(args)
  return unless splat_args_contract_index
  from, count = splat_range(args)
  validate_splat(args, from, count)

  splat_upper_bound = from + count
  return if splat_upper_bound == args.size

  validate_rest(args, from, splat_upper_bound)
end

Private Instance Methods

fail_if_invalid(validator, arg, arg_pos, args_size, contract) click to toggle source
# File lib/contracts/args_validator.rb, line 82
def fail_if_invalid(validator, arg, arg_pos, args_size, contract)
  return if validator && validator.call(arg)
  throw :return, Contracts::CallWith::SILENT_FAILURE unless Contract.failure_callback(
    :arg          => arg,
    :contract     => contract,
    :class        => klass,
    :method       => method,
    :contracts    => contracts,
    :arg_pos      => arg_pos,
    :total_args   => args_size,
    :return_value => false
  )
end
splat_range(args) click to toggle source

splat

  • 2, 3, 4, 5 >>> 0, 4

  • 2 >>> 0, 1

  • 2, 3, 4, 5, 6, 7 >>> 0, 6

# File lib/contracts/args_validator.rb, line 65
def splat_range(args)
  args_after_splat  = args_contracts.size - (splat_args_contract_index + 1)
  in_splat          = args.size - args_after_splat - splat_args_contract_index

  [splat_args_contract_index, in_splat]
end
validate!(args, index, contract = nil, validator = nil) click to toggle source
# File lib/contracts/args_validator.rb, line 72
def validate!(args, index, contract = nil, validator = nil)
  arg       = args[index]
  contract  ||= args_contracts[index]
  validator ||= args_validators[index]
  fail_if_invalid(validator, arg, index + 1, args.size, contract)

  return unless contract.is_a?(Contracts::Func)
  args[index] = Contract.new(klass, arg, *contract.contracts)
end
validate_rest(args, from, splat_upper_bound) click to toggle source
# File lib/contracts/args_validator.rb, line 46
def validate_rest(args, from, splat_upper_bound)
  args[splat_upper_bound..-1].each_with_index do |_arg, index|
    arg_index      = splat_upper_bound + index
    contract_index = from + index + 1
    contract       = args_contracts[contract_index]
    validator      = args_validators[contract_index]
    validate!(args, arg_index, contract, validator)
  end
end
validate_splat(args, from, count) click to toggle source
# File lib/contracts/args_validator.rb, line 37
def validate_splat(args, from, count)
  args.slice(from, count).each_with_index do |_arg, index|
    arg_index = from + index
    contract  = args_contracts[from]
    validator = args_validators[from]
    validate!(args, arg_index, contract, validator)
  end
end