在Ruby中获取调用者模块

时间:2010-01-06 22:18:16

标签: ruby reflection

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

$log.info("Some text here")

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

$log.info("Some text here", self.class.name)

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

有没有办法做到这一点?如果没有,我将只需要处理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

在文件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

3 个答案:

答案 0 :(得分:3)

使用call_stack

首先使用RubyGems安装它:

gem install call_stack

然后将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

适合我(Ruby 1.8.7)。

$ ruby foo.rb
Module: Foo::Bar  Msg: I did something!

答案 1 :(得分:3)

一个mixin解决了OP的具体要求(同时,为了解决通用的“谁叫我”的情况,给了Asher +1。)。

module Log
  module Logger
    def info(msg)
      puts "Module: #{self}  Msg: #{msg}"
    end
  end # class Logger
end # module Log

module Foo
  class Bar
    include Log::Logger
    def do_something
      # Do not pass in self.class.name.
      # We want the output to look like:
      # Module: Foo  Msg: I did something!
      info "I did something!"
    end
  end # class Bar
end # module Foo

foobar = Foo::Bar.new
foobar.do_something

答案 2 :(得分:2)

在为自己的目的寻找答案时遇到过这篇文章。

没有找到合适的,所以我挖掘了Ruby源并组合了一个扩展。我把它捆绑成一个gem-应该安装没有任何问题,只要你使用Ruby 1.9.1:

  

sudo gem install sender

这个对于Ruby 1.8不起作用,因为1.8有一个不同的跟踪帧模型。

http://rubygems.org/gems/sender