[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

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

Ben Harper

9/23/2006 8:04:00 AM

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-....

9 Answers

Ben Harper

9/23/2006 8:22:00 AM

0

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-....

dblack

9/23/2006 8:24:00 AM

0

Marcin Mielzynski

9/23/2006 1:23:00 PM

0

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

Kalman Noel

9/23/2006 1:52:00 PM

0

Marcin MielżyÅ?ski:
> dblack@wobblini.net wrote:
>> 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

e

9/23/2006 3:07:00 PM

0

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-....

Ara.T.Howard

9/23/2006 4:39:00 PM

0

Patrick Spence

3/8/2007 1:57:00 PM

0

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-....

Farrel Lifson

3/8/2007 2:03:00 PM

0

On 08/03/07, Patrick Spence <patrick@pkspence.com> wrote:> Marcin Mielzy?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.Unless you have tight control of your user input you run the riskinjection attacks where you might eval "system('rm -rf /')".Farrel

Patrick Spence

3/8/2007 3:06:00 PM

0

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 :-) 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-....