On 30.04.2007 07:31, Brian Guthrie wrote:
I'd like to be able to change the behavior of a call to a block (I'm
working on a design-by-contract system and would like to be able to
check the block's signature, filtering each call through some contract
check) and I was wondering if anyone had any advice. It's easy enough
to override Proc#call, but doing so doesn't appear to affect calls to
implicit blocks with using the yield keyword. Is it even possible to
do this?
If I understand you properly you want to be checking the argument list
in the *calling* method.
irb(main):003:0> def f(&b)
irb(main):004:1> raise ArgumentError unless b.arity == 4
irb(main):005:1> b[0,1,2,3]
irb(main):006:1> end
=> nil
irb(main):007:0> f {|a,b| p a,b}
ArgumentError: ArgumentError
from (irb):4:in `f'
from (irb):7
from :0
irb(main):008:0> f {|a,b,c,d| p a,b}
0
1
=> nil
Kind regards
robert
It's a bit more complicated than that, but that's the idea. If you're
curious, the library is called Handshake (handshake.rubyforge.org;
haven't made an announcement as it's not quite mature yet). It
supports (among other things) argument contracts of the form:
contract String => Integer
def to_i ...
contract "foo" => 1..3
def foo ...
contract any?( String, hash_of?(Symbol, Fixnum) ) => String
def accepts_string_or_hash ...
The goal is to extend it to support block contracts:
contract [ String, Block(String => Integer) ] => Integer
The Handshake library surrounds an object that includes the
appropriate module with a proxy object and checks everything that
passes across that barrier. That means that I can easily manipulate
any incoming Proc objects, extending the instance so that Proc#call is
required to check an argument list. The problem is that changing the
behavior of Proc#call does _not_ affect the behavior of yield: