On 4/30/07, Robert Klemme <shortcutter / googlemail.com> wrote: > On 30.04.2007 17:10, Brian Guthrie wrote: > > On 4/30/07, Robert Klemme <shortcutter / googlemail.com> wrote: > >> 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: > > Then just create another block that will invoke the original and do the > checks. > > def f(&b) > bb = lambda {|*a| > raise ArgumentError unless a.size == 4 > result = b[*a[0...4]] > raise "Whatever" unless Array === result > result > } > other_method(&bb) > end > > Kind regards > > robert That would work, I think. I'll do that. Thanks for the advice.