Rob Olson's blog



Rob OlsonRob Olson
Second thoughts on initializing modules
edit Posted by Rob Olson on Monday February 15, 2010 at 03:35PM

This morning Yehuda Katz posted a response to my previous post, Technique for extending a method from a module, showing how a more modular organization of the Person class would allow for a solution that does not require a crazy meta programming hack. The idea is that by extracting the method we want to decorate into an ancestor class, Ruby makes it a lot easier to do what we want.

Previously I was aware that there were other ways I could structure the host class to make the module's job easier but I did not try that because but I was writing the code with the knowledge that I would only be in control of one side of the equation, the module. The host class was going to be written by the end-user of the Rubygem the module was to be packaged in. Since I did not want to try dictate how the end-user structured the host class I ended up adding a lot of complexity to the module. The goal became how to write the module in a such a way that the class would "just work" upon including Teacher without requiring any additional steps to be taken. Asking the user to create an AbstractPerson class that contained their initialize method and then creating a subclass felt like an obtrusive request to make through a README that would ultimate negatively impact the user's experience with the library.

Shortly after I put that blog post up I got this tweet from Josh Susser:

Rob OlsonRob Olson
Technique for extending a method from a module
edit Posted by Rob Olson on Sunday February 14, 2010 at 12:17AM
Update: Read the follow-up post Second thoughts on initializing modules

I was recently presented the problem of appending to the initialize method from a module that was being included. To do this it would need to override the class's initialize method with my own but keep the functionality of the original initialize method.

Whenever I need to do something in Ruby that I know will require some experimentation I like to move outside of my application and reproduce the problem in a simple way. For this problem I created a Person class that mixes in a Teacher module.

module Teacher
  def initialize
    puts "initializing teacher"
  end
end

class Person
  include Teacher

  def initialize
    puts "initializing person"
  end
end

The goal is to get the following output when a Person object is created:

> Person.new
initializing teacher
initializing person

The basic program fails as expected; Teacher.new prints "initializing person" because Person's initialize is trumping Teacher's. Our immediate goal is to replace Person's initialize with Teacher's but in a way that preserves the original initialize method. By using alias_method we can create a copy of the original initialize method that we can call later.