正如您在问题中指出的那样以及它记录在红宝石文档 http://ruby-doc.org/core-2.2.0/TracePoint.html#method-i-self, tp.self
返回一个跟踪对象,该对象有一个method
您正在寻找的方法。
我认为你应该使用
method = tp.self.method(tp.method_id)
代替
method = eval("method(:#{tp.method_id})", tp.binding)
UPDATE。关于您有问题的最后一段的一些解释。tp.self
在第一种情况下(当你打电话时foo
) 是指向main
,因为你定义了foo
主要上下文中的方法,它指向String
反对第二种情况,因为sub
在那里定义。但tp.binding.eval("self")
回报main
在这两种情况下,因为它返回一个调用上下文(不是您期望的“定义”上下文),并且在这两种情况下它都是main
.
更新(回复评论)我认为做到这一点的唯一方法是猴子补丁sub
以及您感兴趣的所有其他方法。代码示例:
class String
alias_method :old_sub, :sub
def sub(*args, &block)
old_sub(*args, &block)
end
end
trace = TracePoint.trace(:call, :c_call) do |tp|
tp.disable
case tp.method_id
when :sub
method = tp.self.method(tp.method_id)
puts method.parameters.inspect
end
tp.enable
end
trace.enable
"foo".sub(/(f)/) { |s| s.upcase }
一大缺点是你不能使用$1, $2, ...
原始块中的变量。正如所指出的here https://www.ruby-forum.com/topic/198458哪里没有办法让它发挥作用。但是您仍然可以使用块参数(s
在我的例子中)。