B Seven
B Seven

Reputation: 45943

How to instantiate an object by variable in Ruby?

class Foo
end

class_name = 'Foo'
f = eval(class_name).new
#<Foo:0x007fd3e273ed68>

This example creates the expected instance of Foo.

The class is expected to be defined, but we want to instantiate an object of the class defined in class_name.

The value for class_name is coming from the user, so the above code is a Very Bad Idea™...

Upvotes: 1

Views: 243

Answers (3)

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369428

A class is nothing special. It is just an object assigned to a variable, or in the case of the code you showed, a constant. So, you can use the same metaprogramming methods to retrieve a class from a variable as you would use with any other object: Object#instance_variable_get, Module#class_variable_get, Binding#local_variable_get, Thread#thread_variable_get, or the one which is applicable in this case Module#const_get:

class Foo; end

class_name = 'Foo'
foo = Object.const_get(class_name).new
#=> #<Foo:0x007fd3e273ed68>

foo = self.class.const_get(class_name).new
#=> #<Foo:0x007fd3e273ed68>

Note that the code in the other two answers only works accidentally: they look up Foo in the context of the Module class, which only works because you have actually defined Foo in Object and Module inherits from Object. If you had defined Foo not in an ancestor but in a sibling of Module, then the code in the other two answers wouldn't work:

module Bar; class Foo; end end

Module.const_get(:Foo)
# NameError: uninitialized constant Module::Foo

Bar.const_get(:Foo)
# => Bar::Foo

If you want const_get to behave the same way that normal constant lookup would, you need to call it on the class/module you want to actually look it up in, not on some random class.

Upvotes: 1

JKillian
JKillian

Reputation: 18351

Check out Module::const_get.

class Foo
end

class_name = 'Foo'
myClass = Module.const_get(class_name)
myClass.new

Of course, as the name implies, you can use this to get any kind of constant. So might be wise to check if you're getting a class back:

SOME_CONST = 5
Module.const_get('SOME_CONST').is_a? Class   # => false
Module.const_get('String').is_a? Class       # => true

Upvotes: 2

Matt
Matt

Reputation: 74660

const_get can get a reference to the Class

Module.const_get( :Foo ).new

or

Module.const_get( 'Foo' ).new

Note: in < 1.9 it only searches the current module.

Upvotes: 1

Related Questions