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 ?
Ben H. 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” )?
Ben H. 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).
Hi –
On Sat, 23 Sep 2006, Ben H. 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 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 H. 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 ?
http://rubyforge.org/frs/?group_id=1024&release_id=6580
http://codeforpeople.com/lib/ruby/dynaload/dynaload-0.2.0/README
-a
Marcin MielżyÅ?ski:
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::C”) }}
x.report(“inject”) { n.times{ Object.const_get_recursive(“A::C”)
}}
x.report(“each”) { n.times{ Object.const_get_eaching(“A::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
Marcin Mielżyſski wrote:
[email protected] wrote:
David
I know that eval is not save but it appears that it is much faster than
inject version
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.
[email protected] wrote:
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::C”) } }
x.report(“inject”) { n.times{ Object.const_get_recursive(“A::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
On 08/03/07, Patrick S. [email protected] wrote:
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
Hi –
On 3/8/07, Patrick S. [email protected] wrote:
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
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!