class CptHook::Hookable

A class for extending other classes / modules with before / after hooks.

Public Class Methods

new(obj, method_hooks, additional_contexts = []) click to toggle source
Calls superclass method
# File lib/cpt_hook/hookable.rb, line 9
def initialize(obj, method_hooks, additional_contexts = [])
  super(obj)
  additional_contexts = [additional_contexts] unless additional_contexts.is_a?(Array)
  _add_hooks(:before, method_hooks, additional_contexts)
  _add_hooks(:after, method_hooks, additional_contexts)

  method_hooks.hooked_methods.each do |method|
    define_singleton_method(method) do |*args, &block|
      self.send("before_#{method}") if self.respond_to? "before_#{method}"
      val = super(*args, &block)
      self.send("after_#{method}") if self.respond_to? "after_#{method}"
      val
    end
  end
end

Public Instance Methods

class() click to toggle source
# File lib/cpt_hook/hookable.rb, line 25
def class
  __getobj__.class
end

Private Instance Methods

_add_hooks(which, method_hooks, additional_contexts) click to toggle source
# File lib/cpt_hook/hookable.rb, line 31
def _add_hooks(which, method_hooks, additional_contexts)
  method_hooks.hooks(which).each do |hook|
    define_singleton_method("#{which}_#{hook.method}") do |*args, &block|
      hook.call_chain.each do |call_chain|
        call_args = call_chain.withs.map { |ca| ca == :self ? self : ca }

        if call_chain.method.is_a?(Proc)
          call_chain.method.call(*call_args)
        else
          contexts = call_chain.contexts.concat(additional_contexts).unshift(__getobj__)
          contexts.map!{ |c| c.is_a?(Proc) ? c.call : c }
          context = contexts.find {|c| c.respond_to?(call_chain.method)}
          raise "No context found for #{which} hook: #{call_chain.method}" unless context
          context.send(call_chain.method, *call_args)
        end
      end
    end
  end
end