5

As a follow up to How can I reverse ruby's 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.

Community
  • 1
  • 1
Glenjamin
  • 7,150
  • 6
  • 25
  • 26
  • "This is code that I don't really have access to modify": Is monkey-patching not an option? – Wayne Conrad Mar 09 '10 at 16:13
  • Monkey patching is an option, sort of - but the way the module we're replacing works, It defines the modules and then includes them - it's quite tricky to inject code somewhere into this chain to stop the include happening. Although after pursing this line for a while, I'm starting to lean more in that direction. – Glenjamin Mar 09 '10 at 16:42

1 Answers1

2

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.

crispy
  • 5,737
  • 4
  • 33
  • 45