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

···

--
Posted via http://www.ruby-forum.com/.

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:27 pm, Drew Olson <olso...@gmail.com> wrote:

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

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

···

On Oct 15, 4:51 pm, Phrogz <phr...@mac.com> 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.

Gavin Kistner 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

···

--
Posted via http://www.ruby-forum.com/\.

Drew Olson 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

···

--
Posted via http://www.ruby-forum.com/\.

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

···

--
Posted via http://www.ruby-forum.com/\.

Drew Olson 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

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

···

On Mon, Oct 15, 2007 at 7:52 PM, Drew Olson <olsonas@gmail.com> wrote:
,
.
.
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/

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

···

On Wed, May 14, 2008 at 7:24 PM, Dave Rothlisberger <dave@rothlis.net> wrote:

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

--
Rick DeNatale

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