0

我想用日志记录模块的所有类方法,如下所示:

module SomeModule

  def self.foo
    puts "bar"
  end

  class << self
    SomeModule.methods(false).each do |method|
      alias_method "old_#{method}".to_sym, method
      define_method method do |*args|
        puts "Called method: #{method}"
        send "old_#{method}", *args
      end
    end
  end
end

SomeModule.foo
#-> Called method: foo
#-> bar

这完美无缺。但是如果我希望包装只在我调用一个方法时发生呢?当你打电话时我怎么能做到这一点

module SomeModule
  def self.foo
    puts "bar"
  end

  def self.add_logging_to_all_methods
    #???
  end
end  
SomeModule.add_logging_to_all_methods

SomeModule.foo
#-> Called method: foo
#-> bar
4

3 回答 3

1

我不会问你想要这个做什么,但它是:

module SomeModule

  def self.foo
    puts "bar"
  end

  def self.add_logging_to_all_methods
    eigenclass = class << self; self; end
    methods(false).each do |method|
      eigenclass.class_eval do
        alias_method "old_#{method}".to_sym, method
        define_method method do |*args|
          puts "Called method: #{method}"
          send "old_#{method}", *args
        end
      end
    end
  end
end
SomeModule.add_logging_to_all_methods

SomeModule.foo

请注意,这也会在 中添加“日志记录” add_logging_to_all_methods,但仅在调用它之后,因此如果您只调用它一次,您应该不会看到任何错误。

什么eigenclass意思是您添加此方法的“实例”fooadd_logging_to_all_methods. 通过返回块self内,class << self; end我得到了那个实例。然后我要求在该实例的上下文中评估该块,这与您之前的方法或多或少相同。

可能有更简单的方法来做到这一点。

于 2013-07-18T19:52:42.317 回答
1

您可以将其应用于所有课程:

ObjectSpace.each_object.select { |o| o.is_a? Class }.each do |klass|
  klass.class_eval do
    methods(false).each do |method|
      alias_method "old_#{method}".to_sym, method
      define_method method do |*args|
        puts "Called method: #{method}"
        send "old_#{method}", *args
      end
    end
  end rescue nil
end
于 2013-07-18T19:57:25.123 回答
0

啊没关系,只需将整个 class << self 块放在方法中就可以了。

于 2013-07-18T19:52:38.217 回答