1

Why am I getting an error:

ERROR:

LocalJumpError # ~> no block given (yield) 

CODE:

module M def hello(text = 'bba') puts "yo-#{text}" # => nil end # => :hello instance_methods # => [:hello] m = instance_method(:hello) # => #<UnboundMethod: M#hello> define_method(:bye) do |*args, &block| yield # ~> LocalJumpError: no block given (yield) m.bind(self).(*args, &block) end # => :bye end # => :bye class A include M # => A end # => A A.new.hello('vv') # => nil A.new.bye('zz') do |p| # => #<A:0x00007fa8c401e090> puts "ggg" end # >> yo-vv # ~> LocalJumpError # ~> no block given (yield) 

1 Answer 1

4

It's the difference in the semantics of def and define_method. See this:

module M def outer(&block) puts "outer: #{yield}" def inner1 puts "inner1: #{yield}" end M.define_method(:inner2) do puts "inner2: #{yield}" end M.define_method(:inner3) do |&block| puts "inner3: #{block.call}" end inner1 { 1 } inner2 { 2 } inner3 { 3 } end end class A include M end A.new.outer { 0 } # => outer: 0 # inner1: 1 # inner2: 0 (!!!) # inner3: 3 

yield only works inside def.

Thus, inner1 calls its own block; but inner2 uses the block of the def it is in. The correct way to invoke the block inside define_method is to capture it in the parameter list (as you did), and then use #call or #[] on it, like inner3 demonstrates.

In your code, there is no def around, thus no block is available when you yield. You can use the above method, and replace yield with block.call.

Sign up to request clarification or add additional context in comments.

6 Comments

I'm wondering if this is a more general feature of passing a block to another block. If you pass a block as an argument to a block, do you have to pass it as a Proc?
@BobRodes You can't call a block. You can call a method, or a Proc. You can only pass a block in a method call, since a method call explicitly supports a block syntax: foo { ... }. You cannot pass a block in a Proc call, because a Proc call does not have a special syntax, but uses a method call to do it — and #call and #[] do not accept a block.
Right, I realize you can't call a block, and I saw the reason why the OP was getting the error was that, because of the semantics of define_method, he was trying to pass a block to a block instead of a method definition. So, I'm asking whether if you have block1, and want to pass it to block2, the way to do it is wrap block1 in a Proc object first (by using &whatever in block2's parameter list) and then call it from block2 rather than using yield. In other words, is this a more general principle of which the OP's code is an example?
@BobRodes Again, I don't quite understand what you are asking, since "block" is not something you can have in a variable. If block1 and block2 are both Proc, then block1[block2] (or block1.call(block2)) works if block2 accepts |block|, and block1[&block2]` works if block2 accepts |&block|. However, this works: class A; def m; puts "[#{yield}]"; end end; A.new.method(:m).to_proc.call { 4 }. So you can call a Proc with a block (and have it yield) — as long as it was originally defined with def.
why does yield work in this example? stackoverflow.com/questions/5513558/…
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.