Mar 31

Reopening modules in Ruby

Category: Programming, Ruby

Open class definitions in ruby allow libraries to add functionality to existing objects. Standard practice is to define a module with the new functionality and include it into the existing class ( Jay fields on the subject here ). Unfortunately this model breaks when you want to update a module.

For instance the following doesn’t work:

module ExampleModule
  def original_method
  end
end
 
class ExampleClass
  include ExampleModule
end
#re-open the module and extend
module ExampleModule
  module Extension
    def extension_method
    end
  end
 
  include Extension
end
 
obj = ExampleClass.new
 
obj.original_method    #OK
obj.extension_method #nope!

For whatever reason in ruby 1.9 at least changes to the inclusions of the module are not automatically seen in the class the way a new method in the module itself would be.

Unfortunately there doesn’t appear to be a good way around this. One option is to re-open and directly modify the module, which is what we’re trying to avoid. The other option is to re-include the module after extending it as follows:

class ExampleClass
  include ExampleModule
end
 
obj.extension_method #OK

Unfortunately if you are using open classes as an extension mechanism you are opening yourself up for a lot of confusing problems. Why? Suppose my extension used a module to override original_method (originally provided by ExampleModule) in ExampleClass

module OverrideOriginalMethod
  def original_method
  end
end
 
class ExampleClass
  include OverrideOriginalMethod
end
 
#...update example module...
 
#reinclude ExampleModule so changes take effect
class ExampleClass
  include ExampleModule
end
 
obj.extension_method #OK
 
#oops! This is ExampleModule::original_method
obj.original_method
1 comment

Comments are closed.