Dynamic Namespaced Class Instantiation in Ruby
Lets assume we have a module called Fruit, within the Fruit module is a bunch of Fruit classes.
module Fruit class Apple end class Orange end class WaterMelon end end
If the name of the fruit comes from some data or memory store, and we want to instantiate the class dynamically via the fruit name, you might attempt to do something like this:
>> fruit_name = "Apple"
> "Apple"
>> class_name = "Fruit::#{fruit_name}"
> "Fruit::Apple"
>> klass = Object.const_get(class_name)
NameError: wrong constant name Fruit::Apple
from (irb):14:in `const_get'
from (irb):14The problem here is #const_get does not support retrieving constants within a nested namespace. In order to combat this, we must first retrieve the module in which the class is in, then get the class.
>> Module.const_get("Fruit").const_get(fruit_name)
> Fruit::Apple
>>Here is an example in action:
module Fruit class Apple def self.color "red" end end class Orange def self.color "orange" end end class WaterMelon def self.color "green" end end end %w{Apple Orange WaterMelon}.each do |fruit_name| klass = Module.const_get("Fruit").const_get(fruit_name) puts klass.color end # output red orange green