Skip to content

Instantly share code, notes, and snippets.

@igorkasyanchuk
Last active September 15, 2017 11:22
Show Gist options
  • Save igorkasyanchuk/7972080816fffc86ef299f3eda17c146 to your computer and use it in GitHub Desktop.
Save igorkasyanchuk/7972080816fffc86ef299f3eda17c146 to your computer and use it in GitHub Desktop.
hooks.rb
require 'rubygems'
require 'pry'
class Hooks
def initialize; @callbacks ||= Hash.new({before: [], after: []}) end
def to_s; @callbacks.inspect; end
def register_hook(type, method_name, callback_method = nil, &block)
@callbacks[method_name][type].push(callback_method || block)
end
def invoke(scope_name, method_name, instance)
@callbacks[method_name][scope_name].each do |hook|
if hook.is_a?(Symbol)
instance.send(hook)
else
hook.yield(instance)
end
end
end
end
module Hookable
def self.included(base_klass)
unless Object.const_defined?("#{base_klass.name}Interceptor")
base_klass.extend(ClassMethods)
interceptor = const_set("#{base_klass.name}Interceptor", Module.new)
base_klass.send(:prepend, interceptor)
end
end
module ClassMethods
def hooks; @hooks ||= Hooks.new; end
def hook(type, method_name, callback_method = nil, &block)
interceptor = const_get("#{name}Interceptor")
hooks.register_hook(type, method_name, callback_method, &block)
interceptor.module_eval do
define_method(method_name) do |*args, &block|
self.class.hooks.invoke(:before, method_name, self)
super(*args, &block)
self.class.hooks.invoke(:after, method_name, self)
end
end
end
end
end
class Duck
include Hookable
attr_reader :name
def initialize; @name = 'Skrydzh'; end
hook :before, :make_sound do |object|
puts "In wild-wild forest..."
end
hook :after, :make_sound do |object|
puts "Bang-bang #{object.name}"
end
hook :after, :make_sound do |object|
puts "Kill-kill #{object.name}"
end
hook :after, :make_sound, :end_game
def make_sound; puts "Krya-krya, #{name}"; end
def end_game; puts "Game over"; end
end
duck = Duck.new
duck.make_sound
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment