2012-08-22 9 views
5

Wenn ich Methoden schreiben, die einen optionalen Block nehmen, verwende ich normalerweise so etwas wieWarum funktioniert `block_given?` Nicht in dieser dynamisch definierten Methode?

block.call if block_given? 

in Verfahren jedoch definierte dynamisch wie die unten, block_given? nicht zu funktionieren scheint.

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' } 

Der Block wird wie erwartet aufgerufen, aber block_given? gibt false zurück.

Warum ist das?

Antwort

9

Blöcke sind Verschlüsse, so dass sie sich an lokale Variablen erinnern (zB method_name). Sie erinnern auch Blöcke: yield und block_given? suchen nach dem Block, der zu der Zeit aktiv war, die define_method aufgerufen wurde, nicht der Block, der an bar übergeben wurde. Es gab keinen einzigen, also gibt der gegebene Block die Rückgabe falsch aus.

besseren Veranschaulichung dieser ist

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'} 

die

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