如何重新定义其他类方法的类方法?

时间:2013-07-18 19:03:56

标签: ruby

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

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

3 个答案:

答案 0 :(得分: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,我正在获取该实例。然后我要求在该实例的上下文中对块进行求值,该实例与先前的方法大致相同。

可能有一种更简单的方法。

答案 1 :(得分: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

答案 2 :(得分:0)

啊没关系,只是放置整个班级&lt;&lt;方法中的自我阻止工作正常。