这是我的实现,以开发方式在模型中的所有方法之前运行代码
调用“before_hook:months_used”方法需要在类的底部到ExecutionHooks才能获得在模块中加载的instance_method.我想在顶部加载实例方法
class BalanceChart < BalanceFind include ExecutionHooks attr_reader :options def initialize(options = {}) @options = options @begin_at = @options[:begin_at] end def months_used range.map{|date| I18n.l date,format: :month_year}.uniq! end before_hook :months_used end module ExecutionHooks def self.included(base) base.send :extend,ClassMethods end module ClassMethods def before @hooks.each do |name| m = instance_method(name) define_method(name) do |*args,&block| return if @begin_at.blank? ## the code you can execute before methods m.bind(self).(*args,&block) ## your old code in the method of the class end end end def before_hook(*method_name) @hooks = method_name before end def hooks @hooks ||= [] end end end
解决方法
您可以使用
prepend
执行此操作.prepend就像包含一样,它将一个模块添加到类的祖先,但不是在它之前添加它之后添加它.
这意味着如果在前置模块和类中都存在方法,则首先调用模块实现(如果它想调用基类,它可以选择调用super).
这允许你编写一个钩子模块,如下所示:
module Hooks def before(*method_names) to_prepend = Module.new do method_names.each do |name| define_method(name) do |*args,&block| puts "before #{name}" super(*args,&block) end end end prepend to_prepend end end class Example extend Hooks before :foo,:bar def foo puts "in foo" end def bar puts "in bar" end end
在实际使用中,您可能希望将该模块存储在某处,以便每次调用之前都不会创建新模块,但这只是一个实现详细信息