2012-08-22 9 views
5

Quando scrivo metodi che accettano un blocco opzionale, io di solito usare qualcosa di similePerché "block_given?" Non funziona in questo metodo definito dinamicamente?

block.call if block_given? 

Tuttavia, nel metodo definito come dinamicamente quella qui sotto, block_given? non sembra funzionare.

class Foo 
    %w[bar baz].each do |method_name| 
    define_singleton_method(method_name) do |&block| 
     puts "Was #{method_name} given a block? #{block_given?}" 
     puts block.call 
    end 
    end 
end 

Foo.bar { puts 'I am a block' } 

Il blocco si chiama come previsto, ma block_given? restituisce false.

Perché è questo?

risposta

9

I blocchi sono chiusure, quindi ricordano le variabili locali (ad esempio method_name). Ricordano anche i blocchi: yield e block_given? stanno cercando il blocco che era attivo nel momento in cui è stato chiamato il numero define_method, non il blocco passato a bar. Non ce n'era uno, quindi il blocco dato restituisce false.

meglio illustrare questo è

def create_method 
    define_singleton_method('foo') do |&block| 
    puts "Was given a block? #{block_given?}" 
    puts yield 
    puts block.call 
    end 
end 

create_method {'block passed to create_method'} 
foo {'block passed to the created method'} 

che emette

Was given a block? true 
block passed to create_method 
block passed to the created method