如何通过包含模块来包装 Ruby 方法的调用? [英] How do I wrap the invocation of a Ruby method by including a module?

查看:38
本文介绍了如何通过包含模块来包装 Ruby 方法的调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望在我的某些课程中发生某些事情时收到通知.我想以这样一种方式设置它,即我在这些类中的方法的实现不会改变.

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_methodinstance_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆