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

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_methodinstance_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)


Jak*_*mpl 9

我想你可以使用别名方法链.

像这样的东西:

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)

您不必使用此方法自行修改方法.