Tutorial :How to define a method some how like the 'yield' ( I mean, automatically catch the block)?



Question:

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?).




Solution:1

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.


Solution:2

Something like:

def call_me_3_times &block    yields &block  end  


Solution:3

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  


Solution:4

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  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »