2011-04-05 27 views
5

Tengo problemas para obtener una variable de un bucle for. Parece que i (var) se calcula más adelante y no la definición de clase que necesito totalmente.define_method no usa variables hasta que se llama al método?

ree-1.8.7-2010.02 > class Pat 
ree-1.8.7-2010.02 ?> for i in 39..47 
ree-1.8.7-2010.02 ?> define_method("a#{i}".to_sym) do 
ree-1.8.7-2010.02 >   puts i 
ree-1.8.7-2010.02 ?>  end 
ree-1.8.7-2010.02 ?> end 
ree-1.8.7-2010.02 ?> end 
#=> 39..47 

ree-1.8.7-2010.02 > p = Pat.new 
#=> #<Pat:0x103c31140> 

ree-1.8.7-2010.02 > p.a39 
47 
#=> nil 

ree-1.8.7-2010.02 > p.a49 
NoMethodError: undefined method `a49' for #<Pat:0x103c31140> 
    from (irb):69 
    from :0 
ree-1.8.7-2010.02 > p.a40 
47 
#=> nil 

¿Debo estar utilizando def? si es así, ¿cómo puedo lograr los nombres del método dinámico que logré aquí con def.

Respuesta

7

Lo que está pasando hay un poco sutil ... el tradicional bucle for que estás usando comparte la única variable "i" en todas las iteraciones ... El cierre (bloquear contraseña para definir_metodo) está capturando "i" - y dado que solo hay una "i", todos (al final del ciclo for) capturarán el valor final de "i", que es el último valor en el rango sobre el que está pasando el cursor.

solución alternativa:

class C 
    (1..10).each {|i| define_method("a#{i}") { puts i } } 
end 
3
>> class Pat 
.. (37..47). each do |i| 
..  define_method("a#{i}".to_sym) do 
..   puts i 
..  end 
..  end 
.. end #=> 37..47 
>> Pat.new.a40 #=> nil 
40 
>> Pat.new.a50 
NoMethodError: undefined method `a50' for #<Pat:0x00000100b39bc8> 

Editar: lo siento, no tengo tiempo para una explicación adecuada, pero una búsqueda rápida criado un blog donde podrás obtener el quid de la cuestión: http://paulphilippov.com/articles/enumerableeach_vs_for_loops_in_ruby

2

Aunque la respuesta de @ RyanLeCompte es mejor y más limpia (y suficientemente describe la causa del problema), aquí es una solución alternativa, amoldarse a la forma en que este problema se suele evitarse en JavaScript:

class Foo 
    for i in 1..9 do 
    define_method "a#{i}", &(lambda{|x| lambda{puts x}})[i] 
    end 
end 
Foo.new.a1 
#=> 1 
Foo.new.a9 
#=> 9 

no acepta esta respuesta, pero votan hacia arriba si le ayuda a subir de nivel su metaprogramming. :)

Cuestiones relacionadas