如何通过包含模块来包装 Ruby 方法的调用? [英] How do I wrap the invocation of a Ruby method by including a module?
问题描述
我希望在我的某些课程中发生某些事情时收到通知.我想以这样一种方式设置它,即我在这些类中的方法的实现不会改变.
I want to be notified when certain things happen in some of my classes. I want to set this up in such a way that the implementation of my methods in those classes doesn't change.
我想我会有类似以下模块的东西:
I was thinking I'd have something like the following module:
module Notifications
extend ActiveSupport::Concern
module ClassMethods
def notify_when(method)
puts "the #{method} method was called!"
# additional suitable notification code
# now, run the method indicated by the `method` argument
end
end
end
然后我可以像这样将它混合到我的课程中:
Then I can mix it into my classes like so:
class Foo
include Notifications
# notify that we're running :bar, then run bar
notify_when :bar
def bar(...) # bar may have any arbitrary signature
# ...
end
end
我的主要愿望是我不想修改 :bar
来使通知正常工作.这能做到吗?如果是这样,我将如何编写 notify_when
实现?
My key desire is that I don't want to have to modify :bar
to get notifications working correctly. Can this be done? If so, how would I write the notify_when
implementation?
另外,我使用的是 Rails 3,所以如果有我可以使用的 ActiveSupport 或其他技术,请随时分享.(我查看了 ActiveSupport::Notifications,但这需要我修改 bar
方法.)
Also, I'm using Rails 3, so if there are ActiveSupport or other techniques I can use, please feel free to share. (I looked at ActiveSupport::Notifications, but that would require me to modify the bar
method.)
我注意到我可能想使用模块+超级技巧".我不确定这是什么——也许有人可以启发我?
It has come to my attention that I might want to use "the Module+super trick". I'm not sure what this is -- perhaps someone can enlighten me?
推荐答案
这个问题在这里已经有一段时间了,但还有另一种可能性,可以通过包含(或扩展)的模块来包装方法.
It has been quite a while since this question here has been active, but there is another possibility to wrap methods by an included (or extended) Module.
>
从 2.0 开始,您可以前置 一个模块,有效地使其成为前置类的代理.
Since 2.0 you can prepend a Module, effectively making it a proxy for the prepending class.
在下面的例子中,一个扩展模块模块的方法被调用,传递你想要包装的方法的名称.对于每个方法名称,都会创建并添加一个新模块.这是为了代码简单.您还可以将多个方法附加到单个代理.
In the example below, a method of an extended module module is called, passing the names of the methods you want to be wrapped. For each of the method names, a new Module is created and prepended. This is for code simplicity. You can also append multiple methods to a single proxy.
使用 alias_method
和 instance_method
的解决方案的一个重要区别,后者绑定在 self
上是您可以定义要包装的方法在定义方法本身之前.
An important difference to the solutions using alias_method
and instance_method
which is later bound on self
is that you can define the methods to be wrapped before the methods themselves are defined.
module Prepender
def wrap_me(*method_names)
method_names.each do |m|
proxy = Module.new do
define_method(m) do |*args|
puts "the method '#{m}' is about to be called"
super *args
end
end
self.prepend proxy
end
end
end
使用:
class Dogbert
extend Prepender
wrap_me :bark, :deny
def bark
puts 'Bah!'
end
def deny
puts 'You have no proof!'
end
end
Dogbert.new.deny
# => the method 'deny' is about to be called
# => You have no proof!
这篇关于如何通过包含模块来包装 Ruby 方法的调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!