Hi --

On Fri, 14 Jul 2006, Tom Werner wrote:

> Allow me to present a scenario:
>
> class Firetruck
>   def put_out_fire(options = {})
>      # code
>   end
> end
>
> Pretend Firetruck is in a 3rd party application (like Rails) that is happy to 
> allow plugins to modify core code. Now, let's say I want to write some code 
> that always adds a certain attribute to the options hash. I could do this:
>
> class Firetruck
>   alias_method :__old_put_out_fire, :put_out_fire
>   def put_out_fire(options = {})
>      __old_put_out_fire(options.merge({:nozzle => :big}))
>   end
> end
>
> Which works just fine until someone else comes up with a plugin that wants to 
> modify the same method (doing something similar to me) and just so happens to 
> also use :__old_put_out_fire as THEIR alias. Now we've got my plugin's method 
> as the alias calling itself, which leads to, you know, badness.
>
> So I'm wondering if there's a better way. Perhaps some way to turn Firetruck 
> into an ancestor of itself, so to speak, so that my plugin would create a new 
> Firetruck class, pushing the old Firetruck backward in the chain and allowing 
> me to call super instead and preventing alias_method explosions. Or would 
> that just end up causing more havoc?

I don't know whether it qualifies as "monkeypatching" (I always
thought that meant doing something sloppy and ill-advised, which I
hope I'm not :-) but see if this helps:

   class FireTruck
     def put_out_fire(options = {})
       p options
     end
   end

   FireTruck.class_eval do
     m = instance_method(:put_out_fire)
     define_method(:put_out_fire) do |options|
       m.bind(self).call(options.merge({ :nozzle => "big" }))
     end
   end

   FireTruck.new.put_out_fire(1 => 2)

   # Now someone else uses the alias:
   class FireTruck
     alias old_put_out_fire put_out_fire
     def put_out_fire(options = {})
       puts "New version!"
       old_put_out_fire(options)
     end
   end

   FireTruck.new.put_out_fire(1 => 2)

Output:

{1=>2, :nozzle=>"big"}
New version!
{1=>2, :nozzle=>"big"}


David

-- 
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
http://www.manning.com/black     => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com        => D[avid ]A[. ]B[lack's][ Web]log
dblack / wobblini.net              => me