Active Support 回调¶ ↑
回调是在对象生命周期的关键点运行的代码钩子。典型的用例是让基类定义一组与它提供的其他功能相关的回调,这样子类就可以安装回调来增强或修改基类功能,而无需覆盖或重新定义基类的方法。
混入此模块允许您定义对象生命周期中将支持回调的事件(通过 ClassMethods#define_callbacks),设置要调用的实例方法、proc 或回调对象(通过 ClassMethods#set_callback),并在适当的时间运行已安装的回调(通过 run_callbacks)。
默认情况下,回调会通过抛出 :abort 来中断。有关详细信息,请参阅 ClassMethods#define_callbacks。
支持三种类型回调:before 回调(在特定事件之前运行);after 回调(在事件之后运行);以及 around 回调(围绕事件的块,在 yield 时触发事件)。回调代码可以包含在实例方法、proc 或 lambda 中,或者响应某些预定方法的回调对象中。有关详细信息,请参阅 ClassMethods#set_callback。
class Record include ActiveSupport::Callbacks define_callbacks :save def save run_callbacks :save do puts "- save" end end end class PersonRecord < Record set_callback :save, :before, :saving_message def saving_message puts "saving..." end set_callback :save, :after do |object| puts "saved" end end person = PersonRecord.new person.save
输出
saving... - save saved
命名空间
- 模块 ActiveSupport::Callbacks::CallTemplate
- 模块 ActiveSupport::Callbacks::ClassMethods
- 模块 ActiveSupport::Callbacks::Conditionals
- 模块 ActiveSupport::Callbacks::Filters
方法
常量
| CALLBACK_FILTER_TYPES | = | [:before, :after, :around].freeze |
实例公共方法
run_callbacks(kind, type = nil) 链接
运行给定事件的回调。
按设置顺序调用 before 和 around 回调,yield 块(如果提供),然后按相反顺序调用 after 回调。
如果回调链被中断,则返回 false。否则,返回块的结果;如果没有设置回调,则返回 nil;如果设置了回调但未提供块,则返回 true。
run_callbacks :save do save end
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/callbacks.rb, line 97 def run_callbacks(kind, type = nil) callbacks = __callbacks[kind.to_sym] if callbacks.empty? yield if block_given? else env = Filters::Environment.new(self, false, nil) next_sequence = callbacks.compile(type) # Common case: no 'around' callbacks defined if next_sequence.final? next_sequence.invoke_before(env) env.value = !env.halted && (!block_given? || yield) next_sequence.invoke_after(env) env.value else invoke_sequence = Proc.new do skipped = nil while true current = next_sequence current.invoke_before(env) if current.final? env.value = !env.halted && (!block_given? || yield) elsif current.skip?(env) (skipped ||= []) << current next_sequence = next_sequence.nested next else next_sequence = next_sequence.nested begin target, block, method, *arguments = current.expand_call_template(env, invoke_sequence) target.send(method, *arguments, &block) ensure next_sequence = current end end current.invoke_after(env) skipped.pop.invoke_after(env) while skipped&.first break env.value end end invoke_sequence.call end end end