Forum: Ruby Creating an object from a variable class name

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
62f37a177639ec72a90990a8fa497b56?d=identicon&s=25 RGR (Guest)
on 2006-05-04 20:51
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
Bf6862e2a409078e13a3979c00bba1d6?d=identicon&s=25 Gregory Seidman (Guest)
on 2006-05-04 20:58
(Received via mailing list)
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
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-05-04 21:02
(Received via mailing list)
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
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-05-04 21:05
(Received via mailing list)
On Fri, 5 May 2006, Gregory Seidman 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
2c51fec8183a5d21c4e11b430beabb47?d=identicon&s=25 Patrick Hurley (Guest)
on 2006-05-04 21:08
(Received via mailing list)
On 5/4/06, Gregory Seidman <gsslist+ruby@anthropohedron.net> 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
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-05-04 21:11
(Received via mailing list)
On May 4, 2006, at 3:01 PM, ara.t.howard@noaa.gov 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
2c51fec8183a5d21c4e11b430beabb47?d=identicon&s=25 Patrick Hurley (Guest)
on 2006-05-04 21:20
(Received via mailing list)
On 5/4/06, Patrick Hurley <phurley@gmail.com> 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
89d967359903c639d31e4cad4569f537?d=identicon&s=25 Charlie Bowman (Guest)
on 2006-05-04 21:59
(Received via mailing list)
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.
25e11a00a89683f7e01e425a1a6e305c?d=identicon&s=25 Wilson Bilkovich (Guest)
on 2006-05-04 22:15
(Received via mailing list)
>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
89d967359903c639d31e4cad4569f537?d=identicon&s=25 Charlie Bowman (Guest)
on 2006-05-04 22:21
(Received via mailing list)
Point taken!
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-05-04 22:27
(Received via mailing list)
On May 4, 2006, at 3:57 PM, Charlie Bowman 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.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-05-04 22:55
(Received via mailing list)
On Fri, 5 May 2006, Logan Capaldo 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 ;-)

-a
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-05-04 23:28
(Received via mailing list)
On May 4, 2006, at 4:54 PM, ara.t.howard@noaa.gov 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
Bbc4b3fca1ae3161257a8636145b424d?d=identicon&s=25 Elliot Temple (Guest)
on 2006-05-05 07:13
(Received via mailing list)
On May 4, 2006, at 1:14 PM, Wilson Bilkovich 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 Temple
http://www.curi.us/blog/
This topic is locked and can not be replied to.