Re: Ways to change the behavior of a block
- From: "Brian Guthrie" <btguthrie@xxxxxxxxx>
- Date: Tue, 1 May 2007 00:40:42 +0900
On 4/30/07, Robert Klemme <shortcutter@xxxxxxxxxxxxxx> wrote:
On 30.04.2007 17:10, Brian Guthrie wrote:
> On 4/30/07, Robert Klemme <shortcutter@xxxxxxxxxxxxxx> 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.
.
- References:
- Ways to change the behavior of a block
- From: Brian Guthrie
- Re: Ways to change the behavior of a block
- From: Robert Klemme
- Re: Ways to change the behavior of a block
- From: Brian Guthrie
- Re: Ways to change the behavior of a block
- From: Robert Klemme
- Ways to change the behavior of a block
- Prev by Date: Re: Ways to change the behavior of a block
- Next by Date: Re: DHH vs. WHY style
- Previous by thread: Re: Ways to change the behavior of a block
- Next by thread: Re: Ways to change the behavior of a block
- Index(es):
Relevant Pages
|