2012-08-22 22 views
5

Cuando escribo métodos que toman un bloque opcional, que suelen utilizar algo así como¿Por qué `` block_given? `No funciona en este método definido dinámicamente?

block.call if block_given? 

Sin embargo, en el método definido de forma dinámica como la de abajo, block_given? no parecen funcionar.

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

El bloque se llama como se esperaba, pero block_given? vuelve falsa.

¿Por qué es esto?

Respuesta

9

Los bloques son cierres, por lo que recuerdan las variables locales (por ejemplo, method_name). También recuerdan los bloques: yield y block_given? están buscando el bloque que estaba activo en el momento en que se llamó a define_method, no el bloque pasado a bar. No había uno, por lo que el bloqueo dado devuelve falso.

una mejor ilustración de esto es

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

que emite

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