在Ruby中获取调用者模块

Chr*_*ton 6 ruby reflection

我们有代码在Ruby 1.8.6 Web应用程序中记录数据.你大致如下调用它:

$log.info("Some text here")
Run Code Online (Sandbox Code Playgroud)

现在,在记录的输出中,我想要包含出现该行的模块.我知道Kernel#caller会给我一个数组,我可以提取日志行发生的文件和行号,但我不希望这样.我想要模块,而不是文件名.显而易见的解决方案是修改日志行,使其如下所示:

$log.info("Some text here", self.class.name)
Run Code Online (Sandbox Code Playgroud)

然后解析结果.但是,这不会起作用,因为我试图在默认情况下提取此信息.也就是说,如果程序员忘记指定模块,那么我需要解决方案才能工作,这是日志行的第二个参数.

有没有办法做到这一点?如果没有,我将只需要处理caller数组; 我们的大多数模块都在不同的目录中,因此这将是一个80%的解决方案.

更完整的示例,请原谅轻微的语法错误:

在文件log.rb中:

module Log
  class Logger
    def info(msg, mod = '')
      puts "Module: #{mod}  Msg: #{msg}"
    end
  end # class Logger
end # module Log
$log = Log::Logger.new
Run Code Online (Sandbox Code Playgroud)

在文件foo.rb中:

module Foo
  class Bar
    def do_something
      # Do not pass in self.class.name.
      # We want the output to look like:
      # Module: Foo  Msg: I did something!
      $log.info "I did something!"
    end
  end # class Bar
end #module Foo
Run Code Online (Sandbox Code Playgroud)

Fir*_*aad 3

使用call_stack

首先使用 RubyGems 安装它:

gem install call_stack
Run Code Online (Sandbox Code Playgroud)

然后将log.rb更改为:

require 'rubygems'
require 'call_stack'

call_stack_on

module Log
  class Logger
    def info(msg, mod = '')
        mod = call_stack(2)[0][0] if mod == ''
        puts "Module: #{mod}  Msg: #{msg}"
    end
  end # class Logger
end # module Log
$log = Log::Logger.new
Run Code Online (Sandbox Code Playgroud)

对我有用(Ruby 1.8.7)。

$ ruby foo.rb
Module: Foo::Bar  Msg: I did something!
Run Code Online (Sandbox Code Playgroud)