Как динамически вызывать классы без использования eval?
Вопрос
Можно ли избавиться от оценивать утверждение ниже?Код ниже отфильтровывает все классы, производные от типа BaseClass.После этого создаются экземпляры этих классов и вызывается метод hello.
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
Итак, после выполнения вывод:
привет, мир, я просто шумный класс
привет, мир, здесь был класс А
Я считаю ненужным использование оценивать это зло.И я не уверен, что использование оценивать здесь является обязательным.Есть ли более разумный способ динамического вызова всех классов типа «BaseClass»?
Решение
c = MySpace.const_get(e)
Другие советы
eval — единственный известный мне способ превратить строку в константу.Это даже то, как это делают рельсы:http://api.rubyonrails.com/classes/Inflector.html#M001638
Странно то, что константы возвращают строки.
Вы посмотрели class_eval
вместо?
------------------------------------------------------ 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