views:

119

answers:

1

As a follow up to http://stackoverflow.com/questions/2403057/how-can-i-reverse-rubys-include-function, which was well answered but turned out my simplification of the real problem mean't that the solution was not applicable.

I'm now faced with this (names changed to protect identities!):

module OldFormHelpers
  def foo
    puts "foo"
  end
  def bar
    puts "bar"
  end
end

module Helpers
  include OldFormHelpers
end

This gives me:

Helpers.instance_methods
=> ["bar", "foo"]
Helpers.ancestors
=> [Helpers, OldFormHelpers]

This is code that I don't really have access to modify, without forking.

What I want to do is create a new module;

module BetterFormHelpers
  def foo
    puts "better foo"
  end
end

This needs to remove the behaviours from OldFormHelpers, and then add in the new stuff from BetterFormHelpers

The previous solution was to use undef_method like so:

Helpers.module_eval do
  OldFormHelpers.instance_methods do |m|
    undef_method(m)
  end
end

However, after including BetterFormHelpers, Helpers.instance_methods doesn't contain "foo". The reason for this is explained at http://ruby-doc.org/core/classes/Module.src/M001652.html

Using remove_method tells me that Helpers doesn't have the "foo" method, so I guess I need some way of removing the first inclusion from the ancestors chain...

This was getting a bit long so I stopped putting so many snippets in towards the end, but I add an irb session showing the behaviour of undef/remove and then an include.

+1  A: 

Can't you undefine only the methods that will not be overwritten?

Helpers.module_eval do
  (OldFormHelpers.instance_methods - BetterFormHelpers.instance_methods).each do |m|
    undef_method(m)
  end
end

(The latter included module will be searched first so that no OldFormHelpers method will be executed if BetterFormHelpers also defines it.)

If you want to dynamically overwrite further methods of the OldFormHelpers module, however, the problem remains the same.

duddle