利用set_trace_func方法来判断一个方法是否被alias过
其实就是囧叔跟我说的利用irb的help相同的技巧,在set_trace_func下调用,在合适的binding中取得信息并且直接用throw…catch来跳出(实际并不执行方法体),
详细方法见代码注释:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | def custom_trace(sym, &b) u = method(sym) #得到方法 v = u.arity < 0 ? [] : [0] * u.arity #伪造方法参数 x = lambda{u.call(*v)} #x.call将要调用这个方法,但是实际上不会真的调用 set_trace_func Proc.new ret = catch(:gogogo) do #捕捉gogogo并且返回新的方法名 x.call #执行上述方法 end set_trace_func nil#取消跟踪 ret end def aliased?(sym) sym != custom_trace(sym) do |*e| next unless e[0] == "call" #定位是call throw :gogogo, e[-3] #退出, e[-3]就是当时的方法名 end end def a u puts "Hello" end alias b a p aliased? :b #=> true p aliased? :a #=> false |
顺便,在Ruby1.8的Method没有定义source_location的情况下取得方法定义的位置的方法,以及取得参数名的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | def source_location(sym) custom_trace(sym) do |*e| next unless e[0] == "call" throw :gogogo, eval("[__FILE__, __LINE__]", e[-2]) end end def parameters(sym) custom_trace(sym) do |*e| next unless e[0] == "call" throw :gogogo, eval("local_variables", e[-2]) =begin 第一行就出现的本地变量是一般就是参数 除非有意写成def add(a,b); s = 3 这个方法除了返回"a" "b"还会返回"s" =end end end |