Active Support 回呼
回呼是物件生命週期中關鍵點執行的程式碼掛勾。典型的使用案例是讓基底類別定義一組與其提供的其他功能相關的回呼,以便子類別可以安裝回呼來增強或修改基底功能,而不需要覆寫或重新定義基底類別的方法。
混入這個模組可以定義物件生命週期中將支援回呼的事件(透過 ClassMethods#define_callbacks
),設定要呼叫的實例方法、程序或回呼物件(透過 ClassMethods#set_callback
),並在適當的時間執行已安裝的回呼(透過 run_callbacks
)。
預設情況下,回呼會透過拋出 :abort
來停止。有關詳細資訊,請參閱 ClassMethods#define_callbacks
。
支援三種類型的回呼:before 回呼,在特定事件之前執行;after 回呼,在事件之後執行;以及 around 回呼,圍繞事件的區塊,在 yield 時觸發事件。回呼程式碼可以包含在實例方法、程序或 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 回呼,讓出區塊(如果給定),然後按相反順序執行 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