如何在没有alias_method_chain的情况下在Ruby中修饰方法

时间:2010-12-04 11:50:43

标签: ruby object-model

我们都知道,如果目标类由模块组成,您只需在新模块中调用super即可。但如果它是一个普通的方法呢?

class Logger
  def message(msg)
    puts msg
  end
end

说,Logger是一个我无法改变的类(例如它在宝石中)。 我希望Logger在每条消息之前添加一个“================”行。我如何以美丽的方式做到这一点?遗产?聚合?怎么样?

4 个答案:

答案 0 :(得分:3)

您可以将原始方法保存为未绑定的方法对象,而不是将其保存在别名中。

然后,您可以将define_method与块一起使用。该块将在闭包中捕获未绑定的method_object,允许您在新方法中使用它,而不会污染您的模块/类。

唯一的缺点是,您可能无法定义以这种方式产生或阻塞的方法:

module Mod
  unbound_method = instance_method(:original_method)
  define_method :original_method do |*args|
    #do something before
    #call the original method
    unbound_method.bind(self).call(*args)
    #do something after
  end
end

答案 1 :(得分:2)

这可能不是你所说的“美”,但最简单的方法就是在你的代码中使用:

class Logger
  alias message old_message
  def message(msg)
    puts "================"
    old_message(msg)
  end
end

答案 2 :(得分:2)

您可以从logger继承并使用命名空间来使用它:

class LinedLogger < Logger
  def message(*)
    puts "=" * 15
    super
  end
end

当你想要使用它时:

class Post
  Logger = LinedLogger
end

仅在命名空间Post内,您将获得LinedLogger而不是Logger。这是一种限制补丁的好方法。但它不会在全球范围内发挥作用。

答案 3 :(得分:2)

我会在你自己的实例中执行子类化(每个@ain的答案)或自定义模块包含:

module LoggerLiner
  def message(*args)
    puts "="*15
    super
  end
end

log = Logger.new(STDOUT)
log.extend(LoggerLiner)