9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
# File 'lib/contracts/call_with.rb', line 9
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
|