On Fri, 8 Sep 2006, Logan Capaldo wrote:

> I have this, it takes a different approach though:
>
> module Patchable
>  module ClassMethods
>    def patch(method_name = nil, &new_body)
>      if method_name
>        method_name = method_name.to_sym
>        pre_patched_versions[method_name] = instance_method(method_name)
>        define_method(method_name, &new_body)
>      else
>        klass = Class.new
>        imeths = klass.instance_methods
>        klass.class_eval(&new_body)
>        new_meths = klass.instance_methods - imeths
>        new_meths.each do |m|
>          pre_patched_versions[m.to_sym] = instance_method(m)
>        end
>        class_eval(&new_body)
>      end
>      self
>    end
>
>    def pre_patched_versions
>      @pre_patched_versions ||= {}
>    end
>  end
>
>  def hyper(*args, &block)
>    meth_name = caller[0][/`([^']+)'/, 1].to_sym
>    self.class.pre_patched_versions[meth_name].bind(self).call(*args, &block)
>  end
>
>  def self.included(other)
>    other.extend(ClassMethods)
>  end
> end
>
> class C
>  include Patchable
>
>  def m
>    'a'
>  end
>
>  p new.m
>  patch do
>    def m
>      hyper + 'b'
>    end
>  end
>
>  p new.m
>
>  patch do
>    def m
>      hyper + 'c'
>    end
>  end
>
>  #p new.m doesn't work, infinite recursion
> end
>
> Darn. You seem to have made me discover a bug in my impl. It doesn't work for 
> more than one level of patching per method. Well maybe someone will give me a 
> patch too ;)


heh.  i think you may be hitting the same thing i was.  here's some food for
thought:


this works:

     harp:~ > cat a.rb
     class C
       include Module.new{ def m() 'a' end }
       include Module.new{ def m() super + 'b' end }
       include Module.new{ def m() super + 'c' end }
     end

     p C.new.m


     harp:~ > ruby a.rb
     "abc"


while this does not:

     harp:~ > cat a.rb
     class C
       def m() '' end

       include Module.new{ def m() super + 'a' end }
       include Module.new{ def m() super + 'b' end }
       include Module.new{ def m() super + 'c' end }
     end

     p C.new.m


     harp:~ > ruby a.rb
     ""

even more distilled:

     harp:~ > cat a.rb
     class C
       def m() '' end

       include Module.new{ def m() 'a' end }
     end

     p C.new.m


     harp:~ > ruby a.rb
     ""


i find that behviour quite suprising... in fact, it seems like a bug, but i'm
probably wrong...  thoughts?

cheers.


-a
-- 
what science finds to be nonexistent, we must accept as nonexistent; but what
science merely does not find is a completely different matter... it is quite
clear that there are many, many mysterious things.
- h.h. the 14th dalai lama