tags:

views:

162

answers:

3

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?

+4  A: 
c = MySpace.const_get(e)
Chuck
A: 

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
Keltia
A: 

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.

Squeegy