Creating an object from a variable class name

I want to create an object from a class, but the name of that class is
in a variable, so the form obj=Class.new(args) can’t be used. How can it
be done? Without using eval, because its a bit messy and unelegant.

The equivalent of obj=$variable_with_class_name(args) in php.

Thanks.
RGR

On Fri, May 05, 2006 at 03:51:39AM +0900, RGR wrote:
} I want to create an object from a class, but the name of that class is
} in a variable, so the form obj=Class.new(args) can’t be used. How can
it
} be done? Without using eval, because its a bit messy and unelegant.
}
} The equivalent of obj=$variable_with_class_name(args) in php.

obj = Object::const_get(class_name).new(args)

} Thanks.
} RGR
–Greg

On Fri, 5 May 2006, RGR wrote:

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

   def klass_stamp(hierachy, *a, &b)
     ancestors = hierachy.split(%r/::/)
     parent = Object
     while((child = ancestors.shift))
       klass = parent.const_get child
       parent = klass
     end
     klass::new(*a, &b)
   end

   obj = klass_stamp('String', 'foobar')

-a

On Fri, 5 May 2006, Gregory S. wrote:

On Fri, May 05, 2006 at 03:51:39AM +0900, RGR wrote:
} I want to create an object from a class, but the name of that class is
} in a variable, so the form obj=Class.new(args) can’t be used. How can it
} be done? Without using eval, because its a bit messy and unelegant.
}
} The equivalent of obj=$variable_with_class_name(args) in php.

obj = Object::const_get(class_name).new(args)

mussel:~ > irb -r digest/md5

irb(main):001:0> Digest::MD5.to_s
=> “Digest::MD5”

irb(main):002:0> obj = Object::const_get(“Digest::MD5”).new(args)
NameError: wrong constant name Digest::MD5
from (irb):2:in `const_get’
from (irb):2
from :0

it needs to be a bit smarter than that.

regards.

-a

On May 4, 2006, at 3:01 PM, [email protected] wrote:

Thanks.
klass = parent.const_get child

  • h.h. the 14th dali lama

You know you can do this with inject right?

def klass_stamp(hierachy, *a, &b)
klass = hierachy.split(/::/).inject(Object) { |parent, child|
parent.const_get(child) }
klass.new(*a, &b)
end

On 5/4/06, Patrick H. [email protected] wrote:

} Thanks.
(note I prefer Module. but both work)
pth

Ara is of course correct, so you end up with something like:

klass = var_with_class.to_s.split(‘::’).inject(Module) { |base,klass|
base.const_get(klass) }
obj = klass.new(*args)

If this is a common operation in your code, you could add this into
Module or some other reasonable place.

pth

I understand the ugliness of eval…but why shouldn’t we use it? It is
much quicker to write, shorter to read, and easier to use.

On 5/4/06, Gregory S. [email protected] wrote:

} RGR
–Greg

And if args is an array you want to use as individual params:

obj = Module.const_get(class_name).new(*args)

(note I prefer Module. but both work)
pth

ruby eval_bench.rb
user system total real
eval: 1.141000 0.000000 1.141000 ( 1.156000)
const_get: 0.156000 0.000000 0.156000 ( 0.172000)

cat eval_bench.rb
require ‘benchmark’
class Foo;end
some_class = ‘Foo’
Benchmark.bm(10) do |b|
b.report(“eval:”) { 100000.times {eval("#{some_class}.new")} }
b.report(“const_get:”) {
100000.times{Object.const_get(some_class).new} }
end

On May 4, 2006, at 3:57 PM, Charlie B. wrote:

I understand the ugliness of eval…but why shouldn’t we use it?
It is
much quicker to write, shorter to read, and easier to use.

Some would say ugly is reason enough. It’s also slower in certain
implementations (YARV). The less eval is used, the less it becomes
the common case and if it’s not the common case it doesn’t have to be
fast.

Point taken!

On Fri, 5 May 2006, Logan C. wrote:

You know you can do this with inject right?

not on 1.6.8 - which is still the standard redhat-enterprise install.

that code is years and years old anyhow :wink:

-a

On May 4, 2006, at 4:54 PM, [email protected] wrote:

be kind whenever possible… it is always possible.

  • h.h. the 14th dali lama

No inject in 1.6.8? Gasp!

% cat emergency_inject.rb
module Enumerable
unless instance_methods.include? “inject”
def inject(*seed)
first_item = false
if seed.empty?
first_item = true
else
seed = seed[0]
end
each do |x|
if first_item
seed = x
first_item = false
else
seed = yield(seed, x)
end
end
return seed
end
end
end

On May 4, 2006, at 1:14 PM, Wilson B. wrote:

b.report(“eval:”) { 100000.times {eval(“#{some_class}.new”)} }
b.report(“const_get:”) { 100000.times{Object.const_get
(some_class).new} }
end

We shouldn’t avoid eval just because it takes a second (less on my
computer) to use it 100,000 times. In most situations that is
premature optimisation.

– Elliot T.