ruby - 如何通过包含模块来包装 Ruby 方法的调用?

标签 ruby methods module

我想在我的某些类(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_methodinstance_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/

相关文章:

ruby - 为什么我会收到 #inspect 的 Encoding::CompatibilityError 错误?

javascript - GOOGLE CHARTS 使用实现折线图作为动态数组对象循环

ruby-on-rails - 如何使用 ruby​​ on Rails 创建对多项选择应用程序的投票

objective-c - Objective-C 中的泄漏方法

c# - 如何确定方法是否是泛型方法的泛型实例

类和模块以及 Lua,哦,我的

用于导入模块的 Python 查找文件夹

ruby - 如何与 printf 正确对齐

java - 有成对的执行相同任务的静态方法和实例方法吗?

haskell - 如何导出类型类?