1

我正在编写某种类似于基准测试实用程序的东西,我很好奇是否有一种简单的方法可以从什么上下文中判断一个方法正在被调用。让我举例说明:

module Foo
  my_method
  class Foo
    my_method
    def self.foo
       my_method
    end
    def foo
      my_method
    end
  end
end
Foo::Foo.foo
Foo::Foo.new.foo

理想情况下,对于上述情况,“my_method”将打印如下内容:

在模块“Foo”的定义中调用 在类“Foo”的定义中调用 在类方法“foo”的运行期间调用 在实例方法“foo”的运行期间调用

如果我可以获得对当前“范围”或上下文(或任何 ruby​​ 所称的)的某种引用,这将很容易,但我不知道这是否可能,更不用说如何去做了。谁能指出我正确的方向?

4

4 回答 4

0

Kernel#set_trace_func允许您定义跟踪过程(用于调试/分析目的)。例如:

class Foo
  def self.foo
  end

  def foo
  end
end

set_trace_func proc { |event, file, line, id, binding, classname|
  printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
}

Foo.foo
Foo.new.foo

印刷:

c-return foo.rb:11 set_trace_func   Kernel
    line foo.rb:13                    
    call foo.rb:2         foo      Foo
  return foo.rb:3         foo      Foo
    line foo.rb:14                    
  c-call foo.rb:14        new    Class
  c-call foo.rb:14 initialize BasicObject
c-return foo.rb:14 initialize BasicObject
c-return foo.rb:14        new    Class
    call foo.rb:5         foo      Foo
  return foo.rb:6         foo      Foo
于 2012-11-05T21:39:37.637 回答
0

解决方案

如果您唯一的要求是检测模块定义、类定义和运行方法(类或实例方法)中的方法,那么您将使用以下内容:

def my_method
    if ( a = /^.*?:\d*:in `(.*)'$/.match( caller[0] ) )
        puts ( b = /^<(.*?):(.*?)>$/.match( a[1] ) ) ? 
            "Called in definition of #{b[1].capitalize} \"#{b[2]}\"" :
            "Called during run of #{(self.is_a? Class) ? 'class' : 'instance'} method \"#{a[1]}\""
    end
end

分析

它使用caller包含堆栈跟踪的哪个。第一个正则表达式只解析调用者元素的语法,即:

[file]:[line]:in `<[type]:[name]>'

对于模块和类和

[file]:[line]:in `[method]'

对于方法。

因此,第一个正则表达式删除了该[file]:[line]:in部分。第二个检查是否有<X:Y>模式。

如果是,则表示X包含classmodule可以直接大写,Y包含类或模块的名称。

否则,我们直接拥有方法名称,我们只需要检查它是实例方法还是对象方法。为此,我们只需检查self:如果它是 a 的实例,Class那么我们正在调用类方法,否则我们正在调用实例方法。

测试

在您的示例中,它提供以下输出

在模块“Foo”
的定义中调用 在类“Foo”的定义中
调用 在类方法“foo”
的运行期间调用 在实例方法“foo”的运行期间调用

于 2013-04-13T17:51:58.823 回答
0

尝试这个:

Foo::Foo.method(:foo)
Foo::Foo.new.method(:foo)
于 2012-11-05T22:44:23.260 回答
0

在方法定义中,使用__callee__. 直接在模块内,使用Module.nesting.

于 2012-11-05T23:52:54.713 回答