From: "christophe.poucet@..." Date: 2005-09-21T01:41:38+09:00 Subject: Interesting class Dear, Though mixins are a very nice alternative for multiple inheritance, they do sometimes cause name crashes that are quite annoying. In a recent project I was working on, a design choice I made is that everything would be destroyed with the method 'teardown'. What I mean is that connections are closed, files are closed, etc etc.. As I was refactoring the code, I noticed two pieces of code that could each be put into their own module (factored out). However this led to the fact that both the class that included the module as well as the super class of that class and the class itself had the method teardown. I could've chosen to rename the method inside the extracted module, but instead I came up with quite an interesting and reusable pattern. The idea is that if you have a module with certain methods, you rename those methods to modulenameinlowercase_methodname in the module. It is important that for this to work, the module must be included in the class after any methods with similar names have been defined. (Preferably at the end of the class). Here is the code to the module that contains the necessary functionality: ############################################################################### module Extensible def self.define_aliases(mod, cl, methods) methods.each do |name| mod_name = mod.name.split("::").last.downcase if cl.method_defined?(name) num = 1 while cl.method_defined?("old_#{num}_#{name}") num += 1 end old_name = "old_#{num}_#{name}" cl.module_eval %Q| alias #{old_name} #{name} def #{name}(*args) self.#{mod_name}_#{name} *args self.#{old_name} *args end | else cl.module_eval %Q| alias #{name} #{mod_name}_#{name} | end end end end ############################################################################### It is used as follows in a module that contains functionality that must be mixed in: ############################################################################### module A1 def self.append_features(cl) super methods = %q{test}.split Util.define_aliases(self, cl, methods) end def a1_test puts "A1" end end ############################################################################### Examples: ############################################################################### class B1 def test puts "B1" end end class C1 < B1 def test super puts "C1" end include A1 end C1.new.test => A1 B1 C1 ############################################################################### class D1 < B1 include A1 end D1.new.test => A1 B1 ############################################################################### class E1 include A1 end E1.new.test => A1 ############################################################################### class B2 def test puts "B2" end end class C2 < B2 def test super puts "C2" end include A2 include A1 end C2.new.test => A1 A2 B2 C2 ############################################################################### class D2 < B2 include A2 include A1 end D2.new.test => A1 A2 B2 ############################################################################### class E2 include A2 include A1 end E2.new.test => A1 A2 ############################################################################### Of course this still needs to be extended to work with objects as well, but I thought I would share this. With regards, Christophe