Module: Interloper::ClassMethods

Defined in:
lib/interloper.rb

Instance Method Summary collapse

Instance Method Details

#after(*method_names, &callback) ⇒ Object



100
101
102
103
# File 'lib/interloper.rb', line 100

def after(*method_names, &callback)
  interloper_module.define_interloper_methods(*method_names)
  interloper_module.add_callbacks(:after, *method_names, &callback)
end

#before(*method_names, &callback) ⇒ Object



95
96
97
98
# File 'lib/interloper.rb', line 95

def before(*method_names, &callback)
  interloper_module.define_interloper_methods(*method_names)
  interloper_module.add_callbacks(:before, *method_names, &callback)
end

#generate_interloper_moduleObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/interloper.rb', line 28

def generate_interloper_module
  Module.new do
    class << self
      # @return [Array] The list of available hooks.
      def hooks
        [:before, :after]
      end

      # @return [Hash] The default hash for tracking callbacks to methods.
      def default_callbacks
        {}.tap do |callbacks|
          hooks.each do |hook|
            callbacks[hook] = {}
          end
        end
      end

      # @param [Symbol] hook Optional name of a hook. See .hook method in
      #   this module.
      # @param [Symbol] method_name Optional name of a method.
      # @return [Hash, Array] A hash or array of callbacks. If the 'hook'
      #   param is provided, it will return a hash of callbacks keyed by
      #   method name. If both 'hook' and 'method_name' are provided, will
      #   return an array of callbacks for the given hook and method.
      def callbacks(hook=nil, method_name=nil)
        @callbacks ||= default_callbacks
        if hook && method_name
          # Returns callback stack for a given method and hook. If there
          # aren't callbacks in the stack, return something enumberable to
          # be loop-friendly.
          @callbacks.fetch(hook).fetch(method_name, [])
        elsif hook
          # Return all callbacks for a given hook, e.g. :before.
          @callbacks.fetch(hook)
        else
          @callbacks
        end
      end

      def run_callbacks(hook, method_name, object_context, *orig_args, &orig_block)
        callbacks(hook, method_name).each do |callback|
          object_context.instance_exec *orig_args, &callback
        end
      end

      def add_callbacks(hook, *method_names, &callback)
        method_names.each do |method_name|
          callbacks[hook][method_name] ||= []
          callbacks[hook][method_name] << callback
        end
      end

      def define_interloper_methods(*method_names)
        method_names.each do |method_name|
          define_method(method_name) do |*args, &block|
            called_method = __method__
            interloper_module.run_callbacks(:before, called_method, self, *args, &block)
            return_val = super(*args,&block)
            interloper_module.run_callbacks(:after, called_method, self, *args, &block)
            return_val
          end
        end
      end
    end
  end
end

#interloper_moduleObject

Generates an Interloper module that is namespeced under the including class, if one does not already exist. Then prepends the Interloper module to the including class.

Returns:

  • Module the Interloper module that was prepended to the including class.



20
21
22
23
24
25
26
# File 'lib/interloper.rb', line 20

def interloper_module
  # Create the Interloper module if it doesn't exist already
  const_set(:Interloper, generate_interloper_module) unless self.constants.include? :Interloper
  # Prepend the interloper module
  prepend const_get(:Interloper)
  const_get(:Interloper)
end