i've been wanting a better alias_method for quite some time.
essentially i'd
like a way out of the trap where executing
alias_method '__fubar__', 'fubar'
goes haywire when __fubar__ already exists. we've all seen it
happen before.
anyhow. the interface it'd like would be
class C
def m() 'a' end
push_method 'm'
def m() super + 'b' end
end
p C.new.m #=> 'ab'
what i've got is quite close, but no cigar. it has a fundemental
problem with
the way ruby scopes super which i'm too tired atttm to figure out.
i'm hoping
i can go to bed and wake up to a nice patch
here's what i've got:
harp:~ > cat a.rb
class Module
def push_method m
this = self
include Module.new{
@m = this.instance_method m
this.module_eval{ remove_method m }
module_eval <<-code
def #{ m }(*a, &b)
um = ObjectSpace._id2ref #{ @m.object_id }
um.bind(self).call *a, &b
end
code
}
end
end
class C
def m
'a'
end
p new.m #=> 'a'
push_method 'm'
def m
super + 'b'
end
p new.m #=> 'ab'
push_method 'm'
def m
super + 'c'
end
p new.m #=> 'abc'
end
harp :~ > ruby a.rb
"a"
"ab"
a.rb:31:in `m': stack level too deep (SystemStackError)
from (eval):3:in `m'
from a.rb:31:in `m'
from (eval):3:in `m'
from a.rb:31:in `m'
from (eval):3:in `m'
from a.rb:31:in `m'
from (eval):3:in `m'
from a.rb:31:in `m'
... 2343 levels...
from a.rb:31:in `m'
from (eval):3:in `m'
from a.rb:40:in `m'
from a.rb:42
have at it - i'll be back in 8 hrs. 
I have this, it takes a different approach though:
[Code snipped. You'll have to look above if you want to know how the
broken code works]
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 
caller knows a function only by the name you call it.
hence
class A
def hyper
p caller
end
def a
hyper
end
alias_method :b,:a
end
a=A.new
puts "Calling by a"
a.a
puts "Calling by b"
a.b
gives:
Calling by a
["(irb):7:in `a'", "(irb):14:in `irb_binding'", "/usr/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding'", ":0"]
Calling by b
["(irb):7:in `b'", "(irb):16:in `irb_binding'", "/usr/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding'", ":0"]
In your code, we need to do several things:
* rename and call them by their new names to prevent infinite recursion
* keep track of pre_patched_versions correctly when their name changes
So here's my fix for your code, to incorporate these ideas.
I think that if anyone uses straight up alias_method on methods that we
are patching, things will break, so it's probably a good idea to figure out
how to fix that too.
module Patchable
module ClassMethods
def unused_alias
newalias=nil
while newalias==nil or instance_methods.include?(newalias)
newalias=:"__kenoverride__#{rand(10**20)}__"
end
newalias
end
def patch(method_name = nil, &new_body)
if method_name
method_name = method_name.to_sym
w=unused_alias
alias_method w,method_name
remove_method method_name
pre_patched_versions[w]=pre_patched_versions[method_name.to_sym]\
if pre_patched_versions.include?(method_name.to_sym)
pre_patched_versions[method_name.to_sym] = w
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|
w=unused_alias
alias_method w,m
remove_method m
pre_patched_versions[w]=pre_patched_versions[m.to_sym]\
if pre_patched_versions.include?(m.to_sym)
pre_patched_versions[m.to_sym] = w
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
tocall=self.class.pre_patched_versions[meth_name]
send(tocall,*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
raise StandardError if caller.length>10
hyper + 'b'
end
end
p new.m
patch do
def m
raise StandardError if caller.length>10
hyper + 'c'
end
end
p new.m
#you didn't have a test case for this, but I added it
patch :m do hyper+'d' end
p new.m
end
···
On Fri, 08 Sep 2006 23:09:07 +0900, Logan Capaldo wrote:
On Sep 8, 2006, at 1:34 AM, ara.t.howard@noaa.gov wrote:
--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/