Override methods from a module

D

Drew Olson

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 :eek:ld_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
 
P

Phrogz

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 :eek:ld_setup, :setup
def setup
old_setup
# 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.
 
P

Phrogz

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
 
D

Drew Olson

Gavin said:
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
 
D

Drew Olson

Drew said:
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 :eek:ld_setup, :setup
alias_method :eek:ld_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
 
D

Dave Rothlisberger

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 :eek:ld_setup, :setup
alias_method :eek:ld_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
 
R

Rick DeNatale

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

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

Rick DeNatale

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 :eek:ld_setup, :setup
alias_method :eek:ld_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

Not a general solution:

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

def initialize
super
@@mixer_class.class_eval do
alias_method :eek:ld_setup, :setup
alias_method :eek:ld_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)
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
,
 

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
474,204
Messages
2,571,062
Members
47,669
Latest member
johnmaxwell

Latest Threads

Top