Cómo invocar clases dinámicamente sin necesidad de utilizar eval?
Pregunta
¿Es posible deshacerse de la eval de las siguientes afirmaciones? El código siguiente filtra todas las clases que se derivan de BaseClass tipo. Posteriormente esas clases se crean instancias y el método 'hola' se llama.
module MySpace
class BaseClass
def hello; print "\nhello world"; end
end
class A<BaseClass
def hello; super; print ", class A was here"; end
end
class B<BaseClass
def hello; super; print ", I'm just a noisy class"; end
end
MySpace.constants.each do | e |
c=eval(e)
if c < BaseClass
c.new.hello
end
end
end
Así que después de la ejecución de la salida es:
Hola mundo, soy sólo una ruidosa clase
hola mundo, clase A fue aquí
Creo que el uso innecesario de eval es el mal. Y no estoy seguro de si el uso de eval es obligatorio aquí. Es que hay una manera más inteligente en la invocación de todas las clases de tipo "BaseClass" dinámicamente?
Solución
c = MySpace.const_get(e)
Otros consejos
eval es la única forma que conozco para convertir una cadena en una constante. Sus incluso la forma en rieles lo hace: http://api.rubyonrails.com/classes/Inflector.html#M001638
Lo curioso es que las constantes devuelve cadenas.
¿Has mirado en class_eval
lugar?
------------------------------------------------------ Module#class_eval mod.class_eval(string [, filename [, lineno]]) => obj mod.module_eval {|| block } => obj ------------------------------------------------------------------------ Evaluates the string or block in the context of _mod_. This can be used to add methods to a class. +module_eval+ returns the result of evaluating its argument. The optional _filename_ and _lineno_ parameters set the text for error messages. class Thing end a = %q{def hello() "Hello there!" end} Thing.module_eval(a) puts Thing.new.hello() Thing.module_eval("invalid code", "dummy", 123) produces: Hello there! dummy:123:in `module_eval': undefined local variable or method `code' for Thing:Class