If I need to define a method called 'yields' which will call yiled 3 times:
def yields
3.times do
yield
end
end
开发者_如何学运维And then I will use it in an other method:
def call_me_3_times
yields
end
In the console or irb:
>> call_me_3_times { puts 'me'} # => Cause error
=> LocalJumpError: no block given (yield)
from (irb):32:in `yields'
from (irb):35:in `call_me_3_times'
I hope you can read what I want;
And how to make the 'yields' autolly capture the block given?I mean that when we use the 'yields',we don't need to pass it a '&block', just like the usage of 'yield'(we don't have to even mustn't pass the '&block' to 'yield', need we?).
Something like:
def call_me_3_times &block
yields &block
end
I tried to look at yield implementation to see if we could reproduce its behaviour, but I think it is a keyword, so there's no way to look at the implementation.
I tried with block_given, and looking at the implementation from the ruby core rdocs, I found that block_given? is implemented this way :
rb_f_block_given_p()
{
if (ruby_frame->prev && ruby_frame->prev->iter == ITER_CUR && ruby_block)
return Qtrue;
return Qfalse;
}
As you see, it's C, so it's too low-level implementation. We can't do the same.
If block_given? methods needs to rely on C implementation to just check that a block is given, I can't see how we could get that block and call it within ruby code.
So I think there's no way to do what you want.
You need given a block to you yields method or avoid yield if no block
no yield if no block :
def yields
3.times do
yield if block_given?
end
end
Pass a block to your yields methods
def call_me_3_times
yields { puts 'hello' }
end
A solution to this can be created using the techniques described in this blog post http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
def call_me_three_times
yields &(Proc.new) if block_given?
end
When you define a method as def some_method(&block)
ruby will expect you to pass a block to the method. It will convert that block to a Proc and store it in the block variable.
If you prefix a Proc object with an & it will convert it to a block.
If you call Proc.new within a method and do not provide it with a block then it will create a Proc from the block passed to it.
Some test results are below
def yields
puts "Tripling"
3.times do
yield
end
end
def call_me_three_times
yields &(Proc.new) if block_given?
end
x="Foo"
call_me_three_times { puts x }
x="Bar"
call_me_three_times { puts x }
call_me_three_times
Output
Tripling Foo Foo Foo Tripling Bar Bar Bar
精彩评论