#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
module Callbacks
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def define_callbacks(*names, &block)
names.each do |name|
unless method_defined?("#{name}_with_callback")
define_method(:"#{name}_with_callback") do |*args, &block|
_run_callbacks(:"#{name}", [:before, :around], *args, &block)
result = send(:"#{name}_without_callback", *args, &block)
_run_callbacks(:"#{name}", [:around, :after], *args, &block)
result
end
alias_method :"#{name}_without_callback", :"#{name}"
alias_method :"#{name}", :"#{name}_with_callback"
end
end
end
end
def _callbacks
@_callbacks ||= {}
end
private :_callbacks
def _run_callbacks(name, types, *args, &block)
named_callbacks = _callbacks[name] || {}
types.each do |type|
(named_callbacks[type] || []).each do |callback|
callback.call(*args, &block)
end
end
end
private :_run_callbacks
def _insert_callbacks(names, type, block, options = {})
prepend = options[:prepend]
names.each do |name|
named_callbacks = (_callbacks[:"#{name}"] ||= {})
callbacks = (named_callbacks[type] ||= [])
if prepend
callbacks.unshift block
else
callbacks.push block
end
end
end
private :_insert_callbacks
def _remove_callbacks(names, type, block)
names.each do |name|
named_callbacks = (_callbacks[:"#{name}"] ||= {})
callbacks = (named_callbacks[type] ||= [])
callbacks.delete block
end
end
private :_remove_callbacks
[:before, :after, :around].each do |type|
define_method(:"#{type}_filter") do |*names, &block|
_insert_callbacks(names, type, block)
end
define_method(:"prepend_#{type}_filter") do |*names, &block|
_insert_callbacks(names, type, block, :prepend => true)
end
define_method(:"remove_#{type}_filter") do |*names, &block|
_remove_callbacks(names, type, block)
end
alias_method :"append_#{type}_filter", :"#{type}_filter"
end
end
class Record
include Callbacks
def save(v)
puts "#{v}: - save"
end
define_callbacks :save
end
record = Record.new
record.before_filter :save do |v|
puts "#{v}: saving..."
end
record.after_filter :save do |v|
puts "#{v}: saved"
end
record.save 123
IyEvdXNyL2Jpbi9lbnYgcnVieQojIC0qLSBjb2Rpbmc6IHV0Zi04IC0qLQoKbW9kdWxlIENhbGxiYWNrcwogIGRlZiBzZWxmLmluY2x1ZGVkKGJhc2UpCiAgICBiYXNlLmV4dGVuZCBDbGFzc01ldGhvZHMKICBlbmQKCiAgbW9kdWxlIENsYXNzTWV0aG9kcwogICAgZGVmIGRlZmluZV9jYWxsYmFja3MoKm5hbWVzLCAmYmxvY2spCiAgICAgIG5hbWVzLmVhY2ggZG8gfG5hbWV8CiAgICAgICAgdW5sZXNzIG1ldGhvZF9kZWZpbmVkPygiI3tuYW1lfV93aXRoX2NhbGxiYWNrIikKICAgICAgICAgIGRlZmluZV9tZXRob2QoOiIje25hbWV9X3dpdGhfY2FsbGJhY2siKSBkbyB8KmFyZ3MsICZibG9ja3wKICAgICAgICAgICAgX3J1bl9jYWxsYmFja3MoOiIje25hbWV9IiwgWzpiZWZvcmUsIDphcm91bmRdLCAqYXJncywgJmJsb2NrKQogICAgICAgICAgICByZXN1bHQgPSBzZW5kKDoiI3tuYW1lfV93aXRob3V0X2NhbGxiYWNrIiwgKmFyZ3MsICZibG9jaykKICAgICAgICAgICAgX3J1bl9jYWxsYmFja3MoOiIje25hbWV9IiwgWzphcm91bmQsIDphZnRlcl0sICphcmdzLCAmYmxvY2spCiAgICAgICAgICAgIHJlc3VsdAogICAgICAgICAgZW5kCiAgICAgICAgICBhbGlhc19tZXRob2QgOiIje25hbWV9X3dpdGhvdXRfY2FsbGJhY2siLCA6IiN7bmFtZX0iCiAgICAgICAgICBhbGlhc19tZXRob2QgOiIje25hbWV9IiwgOiIje25hbWV9X3dpdGhfY2FsbGJhY2siCiAgICAgICAgZW5kCiAgICAgIGVuZAogICAgZW5kCiAgZW5kCgogIGRlZiBfY2FsbGJhY2tzCiAgICBAX2NhbGxiYWNrcyB8fD0ge30KICBlbmQKICBwcml2YXRlIDpfY2FsbGJhY2tzCgogIGRlZiBfcnVuX2NhbGxiYWNrcyhuYW1lLCB0eXBlcywgKmFyZ3MsICZibG9jaykKICAgIG5hbWVkX2NhbGxiYWNrcyA9IF9jYWxsYmFja3NbbmFtZV0gfHwge30KICAgIHR5cGVzLmVhY2ggZG8gfHR5cGV8CiAgICAgIChuYW1lZF9jYWxsYmFja3NbdHlwZV0gfHwgW10pLmVhY2ggZG8gfGNhbGxiYWNrfAogICAgICAgIGNhbGxiYWNrLmNhbGwoKmFyZ3MsICZibG9jaykKICAgICAgZW5kCiAgICBlbmQKICBlbmQKICBwcml2YXRlIDpfcnVuX2NhbGxiYWNrcwoKICBkZWYgX2luc2VydF9jYWxsYmFja3MobmFtZXMsIHR5cGUsIGJsb2NrLCBvcHRpb25zID0ge30pCiAgICBwcmVwZW5kID0gb3B0aW9uc1s6cHJlcGVuZF0KICAgIG5hbWVzLmVhY2ggZG8gfG5hbWV8CiAgICAgIG5hbWVkX2NhbGxiYWNrcyA9IChfY2FsbGJhY2tzWzoiI3tuYW1lfSJdIHx8PSB7fSkKICAgICAgY2FsbGJhY2tzID0gKG5hbWVkX2NhbGxiYWNrc1t0eXBlXSB8fD0gW10pCiAgICAgIGlmIHByZXBlbmQKICAgICAgICBjYWxsYmFja3MudW5zaGlmdCBibG9jawogICAgICBlbHNlCiAgICAgICAgY2FsbGJhY2tzLnB1c2ggYmxvY2sKICAgICAgZW5kCiAgICBlbmQKICBlbmQKICBwcml2YXRlIDpfaW5zZXJ0X2NhbGxiYWNrcwoKICBkZWYgX3JlbW92ZV9jYWxsYmFja3MobmFtZXMsIHR5cGUsIGJsb2NrKQogICAgbmFtZXMuZWFjaCBkbyB8bmFtZXwKICAgICAgbmFtZWRfY2FsbGJhY2tzID0gKF9jYWxsYmFja3NbOiIje25hbWV9Il0gfHw9IHt9KQogICAgICBjYWxsYmFja3MgPSAobmFtZWRfY2FsbGJhY2tzW3R5cGVdIHx8PSBbXSkKICAgICAgY2FsbGJhY2tzLmRlbGV0ZSBibG9jawogICAgZW5kCiAgZW5kCiAgcHJpdmF0ZSA6X3JlbW92ZV9jYWxsYmFja3MKCiAgWzpiZWZvcmUsIDphZnRlciwgOmFyb3VuZF0uZWFjaCBkbyB8dHlwZXwKICAgIGRlZmluZV9tZXRob2QoOiIje3R5cGV9X2ZpbHRlciIpIGRvIHwqbmFtZXMsICZibG9ja3wKICAgICAgX2luc2VydF9jYWxsYmFja3MobmFtZXMsIHR5cGUsIGJsb2NrKQogICAgZW5kCgogICAgZGVmaW5lX21ldGhvZCg6InByZXBlbmRfI3t0eXBlfV9maWx0ZXIiKSBkbyB8Km5hbWVzLCAmYmxvY2t8CiAgICAgIF9pbnNlcnRfY2FsbGJhY2tzKG5hbWVzLCB0eXBlLCBibG9jaywgOnByZXBlbmQgPT4gdHJ1ZSkKICAgIGVuZAoKICAgIGRlZmluZV9tZXRob2QoOiJyZW1vdmVfI3t0eXBlfV9maWx0ZXIiKSBkbyB8Km5hbWVzLCAmYmxvY2t8CiAgICAgIF9yZW1vdmVfY2FsbGJhY2tzKG5hbWVzLCB0eXBlLCBibG9jaykKICAgIGVuZAoKICAgIGFsaWFzX21ldGhvZCA6ImFwcGVuZF8je3R5cGV9X2ZpbHRlciIsIDoiI3t0eXBlfV9maWx0ZXIiCiAgZW5kCmVuZAoKCmNsYXNzIFJlY29yZAogIGluY2x1ZGUgQ2FsbGJhY2tzCgogIGRlZiBzYXZlKHYpCiAgICBwdXRzICIje3Z9OiAtIHNhdmUiCiAgZW5kCiAgZGVmaW5lX2NhbGxiYWNrcyA6c2F2ZQplbmQKCnJlY29yZCA9IFJlY29yZC5uZXcKcmVjb3JkLmJlZm9yZV9maWx0ZXIgOnNhdmUgZG8gfHZ8CiAgcHV0cyAiI3t2fTogc2F2aW5nLi4uIgplbmQKcmVjb3JkLmFmdGVyX2ZpbHRlciA6c2F2ZSBkbyB8dnwKICBwdXRzICIje3Z9OiBzYXZlZCIKZW5kCgpyZWNvcmQuc2F2ZSAxMjMKCg==