How to invoke classes dynamically without using eval?
Question
Is it possible to get rid of the eval statement below? The code below filters out all classes which are derived from type BaseClass. Afterwards those classes are instantiated and method 'hello' is called.
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
So after execution the output is:
hello world, I'm just a noisy class
hello world, class A was here
I think unnecessary use of eval is evil. And I'm not sure if the use of eval is mandatory here. Is there is a smarter way in invoking all classes from type "BaseClass" dynamically?
Solution
c = MySpace.const_get(e)
OTHER TIPS
eval is the only way I know of to turn a string into a constant. Its even the way rails does it: http://api.rubyonrails.com/classes/Inflector.html#M001638
The odd thing is that constants returns strings.
Have you looked at class_eval
instead?
------------------------------------------------------ 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