我想在我的某些类(class)中发生某些事情时收到通知。我想以这样一种方式进行设置,即我的方法在这些类中的实现不会改变。
我在想我会有类似以下模块的东西:
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
然后我可以像这样将它混合到我的类中:
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
实现?
此外,我正在使用 Rails 3,所以如果有 ActiveSupport 或其他我可以使用的技术,请随时分享。 (我查看了 ActiveSupport::Notifications ,但这需要我修改 bar
方法。)
我注意到我可能想使用“模块+ super 技巧”。我不确定这是什么 -- 也许有人可以启发我?
最佳答案
自从这里的这个问题一直活跃以来已经有一段时间了,但是还有另一种可能性可以通过包含的(或扩展的)模块来包装方法。
从 2.0 开始,您可以 prepend一个模块,有效地使其成为前置类的代理。
在下面的示例中,调用了扩展模块模块的方法,传递了要包装的方法的名称。对于每个方法名称,都会创建并添加一个新模块。这是为了简化代码。您还可以将多个方法附加到单个代理。
与使用 alias_method
和 instance_method
的解决方案的一个重要区别是,您可以定义要包装的方法在定义方法本身之前。
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 - 如何通过包含模块来包装 Ruby 方法的调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4219277/