ruby - 自定义 Hook /回调/宏方法

标签 ruby metaprogramming

如何在子类中创建自定义 Hook 方法?

当然不需要复制 Rails —— 越简单越好。

我的目标是转化:

class SubClass

  def do_this_method
    first_validate_something
  end
  def do_that_method
    first_validate_something
  end

  private

  def first_validate_something; end
end

收件人:

class ActiveClass; end

class SubClass < ActiveClass
  before_operations :first_validate_something, :do_this_method, :do_that_method

  def do_this_method; end
  def do_that_method; end

  private

  def first_validate_something; end
end

模块中的示例:https://github.com/PragTob/after_do/blob/master/lib/after_do.rb

Rails #before_action:http://apidock.com/rails/v4.0.2/AbstractController/Callbacks/ClassMethods/before_action

最佳答案

这是一个使用prepend 的解决方案。当您第一次调用 before_operations 时,它会创建一个新的(空)模块并将其添加到您的类中。这意味着当您在类上调用方法 foo 时,它将首先在模块中查找该方法。

before_operations 方法然后在此模块中定义简单方法,这些方法首先调用您的“之前”方法,然后使用 super 调用您类中的实际实现。

class ActiveClass
  def self.before_operations(before_method,*methods)
    prepend( @active_wrapper=Module.new ) unless @active_wrapper
    methods.each do |method_name|
      @active_wrapper.send(:define_method,method_name) do |*args,&block|
        send before_method
        super(*args,&block)
      end
    end
  end
end

class SubClass < ActiveClass
  before_operations :first_validate_something, :do_this_method, :do_that_method

  def do_this_method(*args,&block)
    p doing:'this', with:args, and:block
  end
  def do_that_method; end

  private

  def first_validate_something
    p :validating
  end
end

SubClass.new.do_this_method(3,4){ |x| p x }
#=> :validating
#=> {:doing=>"this", :with=>[3, 4], :and=>#<Proc:0x007fdb1301fa18@/tmp.rb:31>}

如果你想让@SteveTurczyn 的想法付诸实践,你必须:

  1. 接收 define_method block 中的 args 参数,而不是它的参数。
  2. 如果您希望能够为它们设置别名,请在定义方法后调用 before_operations

class ActiveClass
  def self.before_operations(before_method, *methods)
    methods.each do |meth|
      raise "No method `#{meth}` defined in #{self}" unless method_defined?(meth)
      orig_method = "_original_#{meth}"
      alias_method orig_method, meth
      define_method(meth) do |*args,&block|
        send before_method
        send orig_method, *args, &block
      end
    end
  end
end

class SubClass < ActiveClass
  def do_this_method(*args,&block)
    p doing:'this', with:args, and:block
  end
  def do_that_method; end

  before_operations :first_validate_something, :do_this_method, :do_that_method

  private    
    def first_validate_something
      p :validating
    end
end

SubClass.new.do_this_method(3,4){ |x| p x }
#=> :validating
#=> {:doing=>"this", :with=>[3, 4], :and=>#<Proc:0x007fdb1301fa18@/tmp.rb:31>}

关于ruby - 自定义 Hook /回调/宏方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36096204/

相关文章:

ruby - 帮助 Ruby 中的元编程 : Overwriting Activerecord Setters

ruby - 为什么 const_missing 不在其前面加上 Object 就不能工作?

ruby-on-rails - carrierwave:在序列化动态属性上安装 uploader

ruby-on-rails - 在 ruby​​ 中通过并行处理有序插入数据

ruby - 如何使用 Watir (Ruby) 从不可见元素中读取文本?

arrays - 修改符号的多维数组

Ruby 将方法定义中的参数括起来

ruby - 使用 Mina 从 github 部署到 Digital Ocean - 卡在 "fetching commits"

c++ - SFINAE 检查继承的成员函数

php - 我可以自动修改/添加语句到 PHP 中的所有用户定义函数吗?