Posterous theme by Cory Watilo

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):14

The 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