如何在没有 alias_method_chain 的情况下在 Ruby 中修饰方法
我们都知道,如果目标类是由模块组成的,则只需在新模块中调用 super
即可。但如果它是类中的普通方法呢?
class Logger
def message(msg)
puts msg
end
end
比如说,Logger 是一个我无法更改的类(例如,它位于 gem 中)。 我希望 Logger 在每条消息之前放置一个“================”行。我如何以一种美观的方式做到这一点?遗产?聚合?如何?
We all know, that if the target class is composed with modules, you can just call super
in a new module. But what if it is an ordinary method in a class?
class Logger
def message(msg)
puts msg
end
end
Say, Logger is a class I can't change (e.g. it is in a gem).
And I want Logger to put a "================" line before each message. How do I do that in a beauty way? Inheritance? Aggregation? How?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以将原始方法保存为未绑定方法对象,而不是将其保存在别名中。
然后,您可以将
define_method
与块一起使用。该块将捕获闭包中未绑定的 method_object ,允许您在新方法中使用它,而不会污染您的模块/类。唯一的缺点是,您可能无法以这种方式定义一个产生或获取块的方法:
You could save the original method as an unbound method object instead of saving it in an alias.
Then, you can use
define_method
with a block. The block will capture the unbound method_object in a closure, allowing you to use it in your new method, without having pollute your module/class.The only downside is, you probably can't define a method that yields to or takes a block in this way:
我要么执行子类化(根据 @iain 的答案),要么在您自己的实例中包含自定义模块:
I would either perform subclassing (per @iain's answer) or a custom module inclusion in your own instances:
这可能不是你所说的“美丽”,但最简单的方法可能是在你的代码中的某个地方:
This may not be what you mean by "beauty" but probably the simplest way is to have, in your code somewhere:
您可以继承 logger 并使用命名空间来使用它:
当您想使用它时:
仅在命名空间
Post
内,您将得到LinedLogger
而不是Logger
。这是限制补丁的好方法。但它不会在全球范围内发挥作用。You could inherit from logger and use namespacing to use it:
And when you want to use it:
Only within the namespace
Post
, you will getLinedLogger
instead ofLogger
. It's a nice way of limiting your patches. It will not work globally though.