Reputation: 45943
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
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
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