How do I instantiate a class who's name is dynamic?

I want to do the following, where 'somefile' is a dynamic value:
require 'somefile.rb'
'somefile.rb' will have a module inside it named "Magic_Module_somefile"
Inside that module there will be a class named "Magic_Class_somefile"
How do I new() that class ?

···

--
Posted via http://www.ruby-forum.com/.

Ben Harper wrote:

I want to do the following, where 'somefile' is a dynamic value:
require 'somefile.rb'
'somefile.rb' will have a module inside it named "Magic_Module_somefile"
Inside that module there will be a class named "Magic_Class_somefile"
How do I new() that class ?

That is, without using eval( magic_etc + ".new" )?

···

--
Posted via http://www.ruby-forum.com/\.

Hi --

I want to do the following, where 'somefile' is a dynamic value:
require 'somefile.rb'
'somefile.rb' will have a module inside it named "Magic_Module_somefile"
Inside that module there will be a class named "Magic_Class_somefile"
How do I new() that class ?

You can get at it using const_get. Here's an irb demo:

irb(main):001:0> s = "somefile"
=> "somefile"
irb(main):002:0> module MM_somefile; class MC_somefile; end; end
=> nil
irb(main):003:0> Object.const_get("MM_#{s}").const_get("MC_#{s}").new
=> #<MM_somefile::MC_somefile:0xb7f85c34>

It's also possible to write a const_get variant that handles the ::
separator automatically:

   class Object
     def const_get_recursive(const)
       const.split("::").inject(Object) {|c1,c2| c1.const_get(c2)}
     end
   end

   const_get_recursive("MM_#{s}::MC::#{s}").new

David

···

On Sat, 23 Sep 2006, Ben Harper wrote:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Ben Harper wrote:

I want to do the following, where 'somefile' is a dynamic value:
require 'somefile.rb'
'somefile.rb' will have a module inside it named "Magic_Module_somefile"
Inside that module there will be a class named "Magic_Class_somefile"
How do I new() that class ?

You want Module#const_get which must be called on the
enclosing class or module (split and inject is the
standard solution for cases where you have a qualified
class name in the ModuleName::ClassName format).

···

--
Posted via http://www.ruby-forum.com/\.

http://rubyforge.org/frs/?group_id=1024&release_id=6580
http://codeforpeople.com/lib/ruby/dynaload/dynaload-0.2.0/README

-a

···

On Sat, 23 Sep 2006, Ben Harper wrote:

I want to do the following, where 'somefile' is a dynamic value:
require 'somefile.rb'
'somefile.rb' will have a module inside it named "Magic_Module_somefile"
Inside that module there will be a class named "Magic_Class_somefile"
How do I new() that class ?

--
in order to be effective truth must penetrate like an arrow - and that is
likely to hurt. -- wei wu wei

dblack@wobblini.net wrote:

  class Object
    def const_get_recursive(const)
      const.split("::").inject(Object) {|c1,c2| c1.const_get(c2)}
    end
  end

  const_get_recursive("MM_#{s}::MC::#{s}").new

David

I know that eval is not save but it appears that it is much faster than inject version

class A
     class B
        C = "foo"
     end
end

n=10000
Benchmark.bm do |x|
     x.report("eval") { n.times{ eval("A::b::C") } }
     x.report("inject") { n.times{ Object.const_get_recursive("A::b::C") } }
end

        user system total real
eval 0.000000 0.000000 0.000000 ( 1.250000)
inject 0.000000 0.000000 0.000000 ( 2.656000)
> Execution finished.

maybe eval does some caching or other kind of optimizations or maybe because it's just c...?

lopex

Marcin Mielżyński:

  class Object
    def const_get_recursive(const)
      const.split("::").inject(Object) {|c1,c2| c1.const_get(c2)}
    end
  end

I know that eval is not save but it appears that it is much faster than
inject version

class A
     class B
        C = "foo"
     end
end

You may speed your method up a little by avoiding blocks with multiple
arguments, as following. Still eval is fastest, though, of course, nobody will
recommend it.

class Object
  def const_get_eaching(const)
    c = Object
    const.split('::').each { |x| c = c.const_get x }
    c
  end
end

n=10000
Benchmark.bm do |x|
     x.report("eval") { n.times{ eval("A::b::C") }}
     x.report("inject") { n.times{ Object.const_get_recursive("A::b::C") }}
     x.report("each") { n.times{ Object.const_get_eaching("A::b::C") }}

end

# Results:

        user system total real
eval 0.100000 0.000000 0.100000 ( 0.101864)
inject 0.210000 0.040000 0.250000 ( 0.258335)
each 0.160000 0.030000 0.190000 ( 0.184249)

Kalman

···

dblack@wobblini.net wrote:

Marcin Mielżyſski wrote:

···

dblack@wobblini.net wrote:

David

I know that eval is not save but it appears that it is much faster than
inject version

<snip>
Just out of curosity, how is "eval()" not safe? I'm doing something very
similar to the OP and have adopted the Object.const_get() approach as
suggested by David. I'd like to get a better understanding of why this
is the preferred method.

--
Posted via http://www.ruby-forum.com/\.

Unless you have tight control of your user input you run the risk
injection attacks where you might eval "system('rm -rf /')".

Farrel

···

On 08/03/07, Patrick Spence <patrick@pkspence.com> wrote:

Marcin Mielżyſski wrote:
> dblack@wobblini.net wrote:
>
>> David
>>
>
> I know that eval is not save but it appears that it is much faster than
> inject version
<snip>
Just out of curosity, how is "eval()" not safe? I'm doing something very
similar to the OP and have adopted the Object.const_get() approach as
suggested by David. I'd like to get a better understanding of why this
is the preferred method.

Hi --

Marcin Mielżyſski wrote:
>
>> David
>>
>
> I know that eval is not save but it appears that it is much faster than
> inject version
<snip>
Just out of curosity, how is "eval()" not safe? I'm doing something very
similar to the OP and have adopted the Object.const_get() approach as
suggested by David. I'd like to get a better understanding of why this
is the preferred method.

eval is not safe in any situation where there's any possibility that
you're executing text of unknown origin or suspicious composition. As
in:

  command = gets.chomp
  eval "system('#{command}')"

An extreme example, but you see the point :slight_smile: When the input is not
suspicious, eval still often has a bit of a flavor of a brute-force
approach to doing things that there might be a more elegant way of
doing.

David

···

On 3/8/07, Patrick Spence <patrick@pkspence.com> wrote:

> dblack@wobblini.net wrote:

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black\)
   (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf\)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

David A. Black wrote:

eval is not safe in any situation where there's any possibility that
you're executing text of unknown origin or suspicious composition. As
in:

  command = gets.chomp
  eval "system('#{command}')"

An extreme example, but you see the point :slight_smile: When the input is not
suspicious, eval still often has a bit of a flavor of a brute-force
approach to doing things that there might be a more elegant way of
doing.

Thanks David and Farrel! Certainly, the Object#const_get() is a much
more elegant approach. Besides eval() smacks too much of the "&" macro
operator used in dBase and it's derivatives... yuck!

···

--
Posted via http://www.ruby-forum.com/\.