Ruby Module Reference
(by Erik Peterson on November 17th 2008)
In Ruby, I always get confused as to the difference between include and extend with modules, and the effect of class << self inside those. So here's a reference script as to what gets included where:
module ExtendedMod def a "a" end class << self def b "b" end end end module IncludedMod def c "c" end class << self def d "d" end end end class Klass def e "e" end class << self def f "f" end end end class SubKlass < Klass def g "g" end # Skip h (ERB::Util.h) class << self def i "i" end end end Klass.extend ExtendedMod Klass.send(:include, IncludedMod) [:a, :b, :c, :d, :e, :f, :g, :i].each do |m| puts "Klass responds to #{m}? #{Klass.respond_to?(m)}" puts "Klass.new responds to #{m}? #{Klass.new.respond_to?(m)}" puts "SubKlass responds to #{m}? #{SubKlass.respond_to?(m)}" puts "SubKlass.new responds to #{m}? #{SubKlass.new.respond_to?(m)}" puts "\n" end
And the output:
Klass responds to a? true Klass.new responds to a? false SubKlass responds to a? true SubKlass.new responds to a? false Klass responds to b? false Klass.new responds to b? false SubKlass responds to b? false SubKlass.new responds to b? false Klass responds to c? false Klass.new responds to c? true SubKlass responds to c? false SubKlass.new responds to c? true Klass responds to d? false Klass.new responds to d? false SubKlass responds to d? false SubKlass.new responds to d? false Klass responds to e? false Klass.new responds to e? true SubKlass responds to e? false SubKlass.new responds to e? true Klass responds to f? true Klass.new responds to f? false SubKlass responds to f? true SubKlass.new responds to f? false Klass responds to g? false Klass.new responds to g? false SubKlass responds to g? false SubKlass.new responds to g? true Klass responds to i? false Klass.new responds to i? false SubKlass responds to i? true SubKlass.new responds to i? false
The takeaways? Don't use class << self in modules. Always put class methods and instance methods in different modules. Use extend for class methods and include for instance methods. I had already "learned" this several times, but for some reason I couldn't remember it until I put this thing together.