我们都知道,如果目标类是由模块组成的,则只需调用super
一个新模块即可。但是如果它是一个类中的普通方法呢?
class Logger
def message(msg)
puts msg
end
end
比如说,Logger 是一个我无法更改的类(例如它在一个 gem 中)。而且我希望 Logger 在每条消息之前放置一个“================”行。我该如何以美丽的方式做到这一点?遗产?聚合?如何?
我们都知道,如果目标类是由模块组成的,则只需调用super
一个新模块即可。但是如果它是一个类中的普通方法呢?
class Logger
def message(msg)
puts msg
end
end
比如说,Logger 是一个我无法更改的类(例如它在一个 gem 中)。而且我希望 Logger 在每条消息之前放置一个“================”行。我该如何以美丽的方式做到这一点?遗产?聚合?如何?
您可以将原始方法保存为未绑定的方法对象,而不是将其保存在别名中。
然后,您可以使用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
我会执行子类化(根据@iain 的回答)或在您自己的实例中包含自定义模块:
module LoggerLiner
def message(*args)
puts "="*15
super
end
end
log = Logger.new(STDOUT)
log.extend(LoggerLiner)
这可能不是您所说的“美”,但可能最简单的方法是在您的代码中某处:
class Logger
alias message old_message
def message(msg)
puts "================"
old_message(msg)
end
end
您可以从 logger 继承并使用命名空间来使用它:
class LinedLogger < Logger
def message(*)
puts "=" * 15
super
end
end
当你想使用它时:
class Post
Logger = LinedLogger
end
只有在命名空间内Post
,您才会LinedLogger
得到Logger
. 这是限制补丁的好方法。但它不会在全球范围内工作。