Skip to content

Instantly share code, notes, and snippets.

@v2e4lisp
Last active August 29, 2015 14:03
Show Gist options
  • Save v2e4lisp/44c6a5b2bc9a2d497f15 to your computer and use it in GitHub Desktop.
Save v2e4lisp/44c6a5b2bc9a2d497f15 to your computer and use it in GitHub Desktop.
ruby before/after hook
module Hooka
class Returning < Struct.new(:value, :returning); end
def self.included(base)
base.extend ClassMethods
end
def returning(value=nil)
throw :hook_stop, Returning.new(value, true)
end
def halt
throw :hook_stop, Returning.new(value, false)
end
def hookable(method)
ret = catch(:hook_stop) { self.run_hooks(:before, method) }
return ret.value if ret.is_a?(Returning) && ret.returning
value = yield
ret = catch(:hook_stop) { self.run_hooks(:after, method) }
ret.is_a?(Returning) && ret.returning ? ret.value : value
end
def run_hooks(before_or_after, met)
self.class.hooks[met][before_or_after].each {|c|
if Symbol === c
method(c).call
else
c.call(self)
end
}
false
end
module ClassMethods
def before(method, callback=nil, &block)
hooks[method][:before] << (callback or block)
end
def after(method, callback=nil, &block)
hooks[method][:after] << (callback or block)
end
def hooks
@__hooks ||= Hash.new {|h, k| h[k] = {:before => [], :after => []} }
end
end
end
# class A
# include Hooka
#
# before :name, :age
# after(:name) {|a| a.returning "after" }
#
# def name(suffix)
# hookable(:name) { "user: " + suffix }
# end
#
# def age
# puts self, "age"
# end
#
# end
#
# a = A.new
#
# puts a.name "wenjun"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment