Skip to content

Instantly share code, notes, and snippets.

@anklos
Created June 11, 2012 23:33
Show Gist options
  • Save anklos/2913422 to your computer and use it in GitHub Desktop.
Save anklos/2913422 to your computer and use it in GitHub Desktop.
simple callbacks
module Callbacks
def self.included(base)
base.class_eval do
extend ClassMethods
include InstanceMethods
end
end
module ClassMethods
def define_callback(callback_name)
callbacks[callback_name] = []
callback_hook =
Proc.new do |*callback_action_and_options|
action = callback_action_and_options[0]
unless action.is_a?(Symbol) or action.respond_to?(:call)
raise "unrecognized callback action: #{action.inspect}"
end
opts = callback_action_and_options[1]
unless !opts or opts.keys.all? { |key| [:if, :unless].include?(key) }
raise "unrecognized callback keys in: #{opts.inspect}"
end
callbacks[callback_name] << [action, opts]
end
singleton = class << self; self end
singleton.send(:define_method, callback_name, callback_hook)
end
def proxy_callback(nominal_name, effective_names)
proxy_hook =
Proc.new do |*callback_action_and_options|
effective_names.each do |effective_name|
send(effective_name, *callback_action_and_options)
end
end
singleton = class << self; self end
singleton.send(:define_method, nominal_name, proxy_hook)
end
def callbacks
@callbacks ||= {}
end
end
module InstanceMethods
def invoke_callback(callback_name)
self.class.callbacks[callback_name].all? do |callback_action, options|
(options and !should_run?(options)) or
(case callback_action
when Symbol
self.send(callback_action)
when Proc
callback_action.call(self)
end != false)
end
end
private
def should_run?(options)
if options[:if]
send(options[:if])
elsif options[:unless]
!send(options[:unless])
else
true
end
end
end
end
module Task
define_callback :after_failure
define_callback :after_success
def failed(name, message)
invoke_callback :after_failure, [name, message]
end
def success(name, message)
invoke_callback :after_success, [name, message]
end
end
module Notify
def self.included(base)
base.class_eval do
extend ClassMethods
include InstanceMethods
end
end
module ClassMethods
after_failure :send_notification
def notify(email, after=5)
@@email = email
@@after = after
end
def send_notification
# send mail
end
end
end
module Record
def self.included(base)
base.class_eval do
extend ClassMethods
include InstanceMethods
end
end
module ClassMethods
after_success :record_success
after_failure :record_failure
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment