Jam*_*ski 7 ruby methods 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
Run Code Online (Sandbox Code Playgroud)
然后我可以将它混合到我的类中,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
我的主要愿望是我不想修改:bar
以使通知正常工作.可以这样做吗?如果是这样,我将如何编写notify_when
实现?
此外,我正在使用Rails 3,所以如果有ActiveSupport或我可以使用的其他技术,请随时分享.(我查看了ActiveSupport :: Notifications,但这需要我修改bar
方法.)
我注意到我可能想要使用"模块+超级技巧".我不确定这是什么 - 也许有人可以启发我?
kos*_*tja 18
已经有一段时间了,因为这里的问题一直很活跃,但是还有另一种方法可以通过包含(或扩展)模块来包装方法.
从2.0开始,您可以添加一个模块,有效地使其成为前置类的代理.
在下面的示例中,调用扩展模块模块的方法,传递要包装的方法的名称.对于每个方法名称,都会创建并预先添加一个新模块.这是为了简化代码.您还可以将多个方法附加到单个代理.
使用的解决方案alias_method
和instance_method
后来绑定的解决方案的一个重要区别self
是,您可以在定义方法本身之前定义要包装的方法.
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
Run Code Online (Sandbox Code Playgroud)
使用:
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!
Run Code Online (Sandbox Code Playgroud)
我想你可以使用别名方法链.
像这样的东西:
def notify_when(method)
alias_method "#{method}_without_notification", method
define_method method do |*args|
puts "#{method} called"
send "#{method}_without_notification", args
end
end
Run Code Online (Sandbox Code Playgroud)
您不必使用此方法自行修改方法.
归档时间: |
|
查看次数: |
6200 次 |
最近记录: |