继承子类的之前或之后钩子

时间:2018-11-27 18:57:45

标签: ruby inheritance module metaprogramming

我编写了一个模块来在实例方法调用之前或之后挂接方法。我想将这些钩子应用于从父类继承的所有类。但是,如果我在父类中编写该钩子,它将不会被执行,只有在子类中存在钩子时,它才会被执行。

这是创建钩子的模块:

module Hooks

def self.included(base)
 base.send :extend, ClassMethods
end


module ClassMethods
  # everytime we add a method to the class we check if we must redifine it
  def method_added(method)
    if @hooker_before && (@methods_to_hook_before.include?(method)|| @methods_to_hook_after.include?(method)) && !@methods_seen.include?(method)
      hooked_method_before = instance_method(@hooker_before) if @hooker_before
      hooked_method_after =  instance_method(@hooker_after) if @hooker_after
      @methods_to_hook_before.each do |method_name|
        begin
          method_to_hook = instance_method(method_name)
        rescue NameError => e
          return
        end
        @methods_seen.push(method)

        define_method(method_name) do |*args, &block|
          hooked_method_before.bind(self).call if hooked_method_before
          method_to_hook.bind(self).(*args, &block) ## your old code in the method of the class
          hooked_method_after.bind(self).call if hooked_method_after
        end
      end
     end
   end

  def before(*methods_to_hook, hookers)
   @methods_to_hook_before = methods_to_hook
   @methods_to_hook_after = [] unless @methods_to_hook_after
   @hooker_before = hookers[:call]
   @methods_seen = []
  end

  def after(*methods_to_hook, hookers)
    @methods_to_hook_after = methods_to_hook
    @methods_to_hook_before = [] unless @methods_to_hook_before
    @hooker_after = hookers[:call]
    @methods_seen = []
  end
 end
end

module Utilities
  def before_generate
    puts("in before generate utilities")
  end
end

class Parent
  include Utilities
  include Hooks


  def generate
    puts("in generate Parent")
  end
end

class Child < Parent
  before :generate, call: :before_generate

  def generate
    puts("in child generate")
  end
end
class AnotherChild < Parent
      before :generate, call: :before_generate

      def generate
        puts("in child generate")
      end
    end

Child.new.generate()产生所需的输出: 在生成实用程序之前 在儿童产生 但是,我希望从Parent继承的所有类都自动从此行为继承。将before :generate, call: :before_generate添加到父类将无法解决问题。是否可以通过将所有子类包装在同一模块中的方法? 有没有一种方法可以实现这一目标,或者我应该在每个需要的子类中重现before调用。

1 个答案:

答案 0 :(得分:0)

您可以对钩子使用可继承的类实例变量,以使其在子类中可用,如here所述。