Concession in an anonymous block

I see no point in the following behavior (see also in this SO thread ):

def def_test puts 'def_test.in' yield if block_given? puts 'def_test.out' end def_test do puts 'def_test ok' end block_test = proc do |&block| puts 'block_test.in' block.call if block puts 'block_test.out' end block_test.call do puts 'block_test' end proc_test = proc do puts 'proc_test.in' yield if block_given? puts 'proc_test.out' end proc_test.call do puts 'proc_test ok' end 

Output:

 def_test.in def_test ok def_test.out block_test.in block_test ok block_test.out proc_test.in proc_test.out 

I don't mind resorting to explicitly declaring the & block variable and calling it directly, but I would like to understand more why I ultimately need to.

+5
source share
2 answers

lambda is a closure and it looks like it captures block_given? and is blocked from its outer area. This behavior makes sense because a block is a more or less implied argument to an external method; you can even grab the block by the named argument if you want:

 def def_test(&block) frobnicate &block end 

Thus, the block is part of the argument list, even if it is not specified.

Consider this simple piece of code:

 def f lambda do puts "\tbefore block" yield if block_given? puts "\tafter block" end end puts 'Calling fw/o block' x = f; x.call puts puts 'Calling fw/ block' x = f { puts "\t\tf-block" }; x.call puts puts 'Calling fw/o block but x with block' x = f; x.call { puts "\t\tx-block" } puts puts 'Calling fw/ block and x with block' x = f { puts "\t\tf-block" }; x.call { puts "\t\tx-block" } 

For me, the following is obtained: 1.9.2:

 Calling fw/o block before block after block Calling fw/ block before block f-block after block Calling fw/o block but x with block before block after block Calling fw/ block and x with block before block f-block after block 

In addition, Proc#call (AKA proc === ) does not accept a block:

prc === obj → result_of_proc
Calls a block, with obj as the parameter of the block. This means that the proc object is the when target in the case expression.

Compare the first line with the documentation for Enumerable#chunk (for example):

enum.chunk {| elt | ...} → an_enumerator

{...} indicates that chunk documented to take a block, the absence of such designations for Proc#call means that Proc#call does not accept a block.

This is not a completely authoritative answer, but perhaps it clears a little.

+4
source

block_given? considers the def region, not the lambda region:

 def test l = lambda do yield if block_given? end l.call end test { puts "In block" } 
+5
source