method_added中调用的未定义自模块方法

时间:2017-09-08 09:06:18

标签: ruby metaprogramming

我正在尝试为类方法实现一个钩子,比如(version 1) (allow default) (deny network*) before_action。问题是如果我在模块内定义一个方法,after_actiondefine_method内的def do_before; puts 'do_before called'; end通常未定义。那么如何在method_added内调用module method

method_added

2 个答案:

答案 0 :(得分:1)

那是因为你正在使用   - extend

  

将指定模块的方法和常量添加到目标   元类

但您还需要 - include

  

它混合了指定模块的方法作为实例方法   目标类

# some code goes here

class Bar
  extend Hooker
  include Hooker

  before_action 'foo2'
  after_action 'bar2'

  def my_func
    puts 'MyFunc called'
  end
end

Bar.new.my_func
=> before_action called with parameter foo2
=> after_action called with parameter bar2
=> do_before called
=> MyFunc called
=> do_after called

更明确的是将其与不同的模块分开。

答案 1 :(得分:0)

以下是另一种解决方案,您无需在课程中明确调用extendinclude

module Hooker
  def self.included(klass)
    klass.extend ClassMethods
  end

  module ClassMethods
    [:before, :after].each do |element|
      define_method("#{element}_action") do |name|
        puts "#{element}_action called with parameter #{name}"
      end
      define_method("do_#{element}") do
        puts "do_#{element} called"
      end
    end
  end

  def method_added(name)
    return if @filtering # Don't add to original_ methods
    @filtering = true

    alias_method :"original_#{name}", name
    define_method name do |*args|
      do_before
      self.send("original_#{name}", *args)
      do_after
    end

    @filtering = false
  end
end

class Bar
  include Hooker

  before_action 'foo2'
  after_action 'bar2'

  def my_func
    puts 'MyFunc called'
  end
end

Bar.new.my_func

这里的诀窍是Hooker模块现在extend 虽然 include