Description
Since #242 (Func contract's return value isn't enforced with blocks) was fixed in contracts-0.15, given blocks are being put into a lambda. So the forwarded block isn't 100% identical with the original one. Especially it's arity
and it's source_location
changed.
Please keep as many properties as possible of the original block, especially the arity.
Or find a way to forward the original block without breaking #242 again. So the original block could be kept. I'd really appreciate any ideas for this, because it might be the cleanest solution!
Commit for #242, introducing this bug: 13e56bd#diff-a45dd775c2769b9ab16a23f9d4560adc
lib/contracts/call_with.rb
@@ -73,7 +75,8 @@ module Contracts
method.call(*args, &blk)
else
# original method name referrence
- method.send_to(this, *args, &blk)
+ added_block = blk ? lambda { |*params| blk.call(*params) } : nil
+ method.send_to(this, *args, &added_block)
end
unless @ret_validator[result]
I especially need the arity to stay unchanged. Some examples about arity:
def a(&b)
puts b.arity
end
a {|x| puts x}
=> 1
a {|x,y| puts x+y}
=> 2
a {puts ''}
=> 0
a {|*x| puts x}
=> -1
A very "simple" way how to keep the arity is using eval (see below). But I hope we find a better way.
--- a/lib/contracts/call_with.rb
+++ b/lib/contracts/call_with.rb
@@ -81,7 +81,15 @@ module Contracts
method.call(*args, &blk)
else
# original method name reference
- added_block = blk ? lambda { |*params| blk.call(*params) } : nil
+ added_block = nil
+ if blk
+ params_ary = []
+ for i in 1..blk.arity
+ params_ary << 'x_'+i.to_s
+ end
+ params_str = params_ary.join(',')
+ added_block = eval('lambda { |'+params_str+'| blk.call('+params_str+') }')
+ end
method.send_to(this, *args, &added_block)
end