def call_with_inner(returns, this, *args, **kargs, &blk)
args << blk if blk
nil_block_appended = maybe_append_block!(args, blk)
if @kargs_validator && !@kargs_validator[kargs]
data = {
arg: kargs,
contract: kargs_contract,
class: klass,
method: method,
contracts: self,
arg_pos: :keyword,
total_args: args.size,
return_value: false,
}
return ParamContractError.new("as return value", data) if returns
return unless Contract.failure_callback(data)
end
(@args_contract_index || args.size).times do |i|
contract = args_contracts[i]
arg = args[i]
validator = @args_validators[i]
unless validator && validator[arg]
data = {
arg: arg,
contract: contract,
class: klass,
method: method,
contracts: self,
arg_pos: i+1,
total_args: args.size,
return_value: false,
}
return ParamContractError.new("as return value", data) if returns
return unless Contract.failure_callback(data)
end
if contract.is_a?(Contracts::Func) && blk && !nil_block_appended
blk = Contract.new(klass, arg, *contract.contracts)
elsif contract.is_a?(Contracts::Func)
args[i] = Contract.new(klass, arg, *contract.contracts)
end
end
if @args_contract_index
splat_upper_index = @args_contract_index
(args.size - @args_contract_index).times do |i|
arg = args[args.size - 1 - i]
if args_contracts[args_contracts.size - 1 - i].is_a?(Contracts::Args)
splat_upper_index = i
end
j = i < splat_upper_index ? i : splat_upper_index
contract = args_contracts[args_contracts.size - 1 - j]
validator = @args_validators[args_contracts.size - 1 - j]
unless validator && validator[arg]
return unless Contract.failure_callback({
:arg => arg,
:contract => contract,
:class => klass,
:method => method,
:contracts => self,
:arg_pos => i - 1,
:total_args => args.size,
:return_value => false,
})
end
if contract.is_a?(Contracts::Func)
args[args.size - 1 - i] = Contract.new(klass, arg, *contract.contracts)
end
end
end
args.slice!(-1) if blk || nil_block_appended
result = if method.respond_to?(:call)
method.call(*args, **kargs, &blk)
else
target_blk = blk
target_blk = lambda { |*params| blk.call(*params) } if blk.is_a?(Contract)
method.send_to(this, *args, **kargs, &target_blk)
end
unless @ret_validator[result]
Contract.failure_callback({
arg: result,
contract: ret_contract,
class: klass,
method: method,
contracts: self,
return_value: true,
})
end
this.verify_invariants!(method) if this.respond_to?(:verify_invariants!)
if ret_contract.is_a?(Contracts::Func)
result = Contract.new(klass, result, *ret_contract.contracts)
end
result
end