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 ?
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" )?
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
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).
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
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
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)
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 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.
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 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:
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!