2010-02-18 12 views
17

Si un bloque es un cierre, ¿por qué este código no funciona y cómo hacerlo funcionar?El cierre no funciona

def R(arg) 
    Class.new do 
    def foo 
     puts arg 
    end 
    end 
end 

class A < R("Hello!") 
end 

A.new.foo #throws undefined local variable or method `arg' for #<A:0x2840538> 
+0

Puede vemos tus mensajes de error? – samoz

+0

El mensaje de error está bajo comentario en la muestra. – yukas

+0

@Earlz, gracias por la edición. – yukas

Respuesta

26

bloques son cierres y arg es de hecho disponible dentro del bloque Class.new. Simplemente no está disponible dentro del método foo porque def inicia un nuevo ámbito. Si se reemplaza con defdefine_method, que tiene un bloque, verá el resultado deseado:

def R(arg) 
    Class.new do 
     define_method(:foo) do 
      puts arg 
     end 
    end 
end 

class A < R("Hello!") 
end 

A.new.foo # Prints: Hello! 
+0

¿cómo se definiría un método que toma los parámetros? – Geo

+2

@Geo: usando un bloque que toma parámetros. P.ej. 'define_method (: add_one) do | x | x + 1 final' – sepp2k

5

Si se define la clase de forma dinámica, puede modificar a su gusto:

def R(arg) 
    c = Class.new 

    # Send the block through as a closure, not as an inline method 
    # definition which interprets variables always as local to the block. 
    c.send(:define_method, :foo) do 
    arg 
    end 

    c 
end 

class A < R("Hello!") 
end 

puts A.new.foo.inspect 
# => "Hello!"