Override methods from a module

All -

I’d like to create a module that adds some specific functionality to my
setup and teardown methods within a few of my test cases. I’d like to be
able to do something to the effect of:

module Stuff
method_alias :old_setup, :setup
def setup
old_setup
# new stuff goes here
end
end

class MyTest
include Stuff
def setup
# original setup stuff here
end
end

The above code is just psuedo code and doesn’t work for a number of
reasons. However, I was wondering if there is a best practice for this
type of behavior.

Thanks,
Drew

On Oct 15, 4:27 pm, Drew O. [email protected] wrote:

# new stuff goes here

end
end

class MyTest
include Stuff
def setup
# original setup stuff here
end
end

I’ve never done this before, but here’s a hack that sort of does what
I think you want:

module Foo
def initialize( *args )
self.extend Foo::Stuff
end
module Stuff
def bar
puts “from module”
super
end
end
end

class Bar
include Foo
def initialize( name )
@name = name
super
end
def bar
puts “from class”
end
end

goof = Bar.new( ‘Goofy’ )
goof.bar
#=> from module
#=> from class

END

Note that this requires calling super in the initialize of the source
class, which may break other ancestor modules/classes expecting
different arguments to be passed in. Ideally the module would latch
onto and wrap the initialize method itself when included in the class,
but I was too lazy to do that.

On Oct 15, 4:51 pm, Phrogz [email protected] wrote:

Note that this requires calling super in the initialize of the source
class, which may break other ancestor modules/classes expecting
different arguments to be passed in. Ideally the module would latch
onto and wrap the initialize method itself when included in the class,
but I was too lazy to do that.

Here’s a slightly cleaner version, showing that you can fully wrap the
class method.

module Foo
def initialize( *args )
self.extend Foo::Stuff
end
module Stuff
def bar
puts “before class”
super
puts “after class”
end
end
end

class Bar
include Foo
def initialize
super
end
def bar
puts “in class”
end
end

goof = Bar.new
goof.bar
#=> before class
#=> in class
#=> after class

Drew O. wrote:

Your examples definitely help and may have helped me with another way of
looking at the problem but I’m not sure they’ll work as my objects are
already extending parent objects.

  • Drew

Sorry about the previous response. Apparently lack of sleep results in
horrendous grammar. Below is the solution I’ve figured out for the
problem. It seems to work the way I was hoping for. Please let me know
if this makes sense/how this could be improved.

Thanks,
Drew

module Stuff
def self.included mod
@@mixer_class = mod
end

def initialize
super
@@mixer_class.class_eval do
alias_method :old_setup, :setup
alias_method :old_teardown, :teardown

  define_method(:setup) do
    old_setup
    puts "new setup"
  end

  define_method(:teardown) do
    old_teardown
    puts "new teardown"
  end
end

end
end

class Tester
def common
puts “this is in all tests!”
end
end

class PlainTester < Tester
def setup
puts “plain setup”
end

def teardown
puts “plain teardown”
end
end

class ExtraFunTester < Tester
include Stuff
def setup
puts “old setup”
end

def teardown
puts “old teardown”
end
end

p = PlainTester.new
e = ExtraFunTester.new

p.setup
p.teardown

e.setup
e.teardown

Gavin K. wrote:

goof = Bar.new
goof.bar
#=> before class
#=> in class
#=> after class

Gavin -

Thanks for the responses. I think you’re examples are interesting,
however I’m not sure this will help me as my objects are already in
inheritance chains. Ideally, I want to be able to include a module that
will “magically” add functionality to existing methods without forcing
any other code changes. Obviously this presents some challenges.
Initially, I figured I would be able to alias the current method,
override the existing method in the module and then call the original
version when I was done. However, because I was including the module at
the top of the class it was not yet able to see that the setup/teardown
methods existed yet.

Your examples definitely help and may have helped me with another way of
looking at the problem but I’m not sure they’ll work as my objects are
already extending parent objects.

  • Drew

Please let me know if this makes sense/how this could be improved.

module Stuff
def self.included mod
@@mixer_class = mod
end

def initialize
super
@@mixer_class.class_eval do
alias_method :old_setup, :setup
alias_method :old_teardown, :teardown

  define_method(:setup) do
    old_setup
    puts "new setup"
  end

  define_method(:teardown) do
    old_teardown
    puts "new teardown"
  end
end

end
end

A slightly nicer way to write the above:

module Stuff
def self.included(mod)
mod.class_eval do
alias_method_chain :setup, :new_feature
end
end

def setup_with_new_feature
setup_without_new_feature
puts ‘new setup’
end

def teardown_with_new_feature
teardown_without_new_feature
puts ‘new teardown’
end
end

On Wed, May 14, 2008 at 7:24 PM, Dave R. [email protected]
wrote:

  alias_method :old_setup, :setup
  end

end
end
end

alias_method_chain, nice as it is, is part of activesupport (i.e. part
of Rails) and is not standard Ruby.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On Mon, Oct 15, 2007 at 7:52 PM, Drew O. [email protected] wrote:

if this makes sense/how this could be improved.
super
old_teardown
end
end
end
Not a general solution:

module Stuff
def self.included mod
@@mixer_class = mod
end

def initialize
super
@@mixer_class.class_eval do
alias_method :old_setup, :setup
alias_method :old_teardown, :teardown

 define_method(:setup) do
   old_setup
   puts "new setup"
 end

 define_method(:teardown) do
   old_teardown
   puts "new teardown"
 end

end
end
end

class Tester
def common
puts “this is in all tests!”
end
end

class PlainTester < Tester
def setup
puts “plain setup”
end

def teardown
puts “plain teardown”
end
end

class ExtraFunTester < Tester
include Stuff
def setup
puts “old setup”
end

def teardown
puts “old teardown”
end
end

class FunkedUpTester < Tester
include Stuff
def setup
puts “old setup”
end

def teardown
puts “old teardown”
end
end

p = PlainTester.new
e = ExtraFunTester.new
f = FunkedUpTester.new

puts “p.setup”
p.setup
p.teardown

puts “e.setup”
e.setup
e.teardown

puts “f.setup”
f.setup
f.teardown

RubyMate r8136 running Ruby r1.8.6
(/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby)

untitled

p.setup
plain setup
plain teardown
e.setup
old setup
old teardown
f.setup
SystemStackError: stack level too deep

method setup in untitled document at line 13
method old_setup in untitled document at line 13
method setup in untitled document at line 13
method old_setup in untitled document at line 13
method setup in untitled document at line 13
method old_setup in untitled document at line 13
method setup in untitled document at line 13
,
.
.
method old_setup in untitled document at line 13
method setup in untitled document at line 13
at top level in untitled document at line 78


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/