Interesting class

C

christophe.poucet

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
 
R

Robert Klemme

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).

Wouldn't it be simpler to do

class Object
def teardown() end
end

and in each module and class

module Foo
def teardown
# local cleanup
super
end
end

?

Kind regards

robert
 
C

christophe.poucet

Not if you have the following pattern:

class Base
def teardown
# do a
end
end

module Foo
def teardown
# do b
end
end

class Child < B
include Foo
def teardown
# call super and my own Foo.teardown somehow
# do c
end
end

Regards,
Christophe
 
R

Robert Klemme

Not if you have the following pattern:

class Base
def teardown
# do a
end
end

module Foo
def teardown
# do b
end
end

class Child < B
include Foo
def teardown
# call super and my own Foo.teardown somehow
# do c
end
end

Regards,
Christophe

Why? Did you test my approach?

robert
 
C

christophe.poucet

You are correct, which is rather odd as I would think that the teardown
defined in Child would override the teardown defined in Foo.

Well I guess the submitted code is pointless :/

Thanks for the suggestion, robert.

Christophe
 
R

Robert Klemme

You are correct, which is rather odd as I would think that the
teardown defined in Child would override the teardown defined in Foo.

Well I guess the submitted code is pointless :/

Thanks for the suggestion, robert.

You're welcome! As an additional hint to an explanation you can look at the
inheritance chain by invoking #ancestors:

$ ruby -e 'module Mod end; class Base; end; class Derived < Base; include
Mod end; p Derived.ancestors'
[Derived, Mod, Base, Object, Kernel]

That's exactly the line along which super works.

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top