Module: BBLib::Hooks
- Defined in:
- lib/bblib/core/mixins/hooks.rb
Overview
Adds method hooking capability to a class. Intended to be used as a mixin.
Instance Method Summary collapse
- #_add_hooked_method(type, hook, method) ⇒ Object
- #_defining_hook? ⇒ Boolean
-
#_hook_after_method(method, hook, opts = {}) ⇒ Object
Current opts: send_args - Sends the arguments of the method to the after method.
-
#_hook_before_method(method, hook, opts = {}) ⇒ Object
Current opts: send_args - Sends the arguments of the method to the before hook.
- #_hook_method(method, force: false) ⇒ Object
- #_hooked_methods ⇒ Object
- #_hooks ⇒ Object
-
#_superclass_hooks ⇒ Object
def _hook_all _hooks.each do |type, hooks| hooks.each do |hook, data| data.each do |method| _hook_method(method) end end end end.
- #method_added(method) ⇒ Object
- #singleton_method_added(method) ⇒ Object
Instance Method Details
#_add_hooked_method(type, hook, method) ⇒ Object
71 72 73 74 75 |
# File 'lib/bblib/core/mixins/hooks.rb', line 71 def _add_hooked_method(type, hook, method) history = _hooked_methods[type] history[hook] = {} unless history[hook] history[hook][method] = instance_method(method) end |
#_defining_hook? ⇒ Boolean
77 78 79 |
# File 'lib/bblib/core/mixins/hooks.rb', line 77 def _defining_hook? @_defining_hook ||= false end |
#_hook_after_method(method, hook, opts = {}) ⇒ Object
Current opts: send_args - Sends the arguments of the method to the after method. send_value - Sends the return value of the method to the hook method. send_value_ary - Sends the return value of the method to the hook method
> with the splat operator.
modify_value - Opts must also include one of the two above. Passes the returned
> value of the method to the hook and returns the hooks value
> rather than the original methods value.
send_all - Sends a hash containing the args, method and value (return).
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/bblib/core/mixins/hooks.rb', line 120 def _hook_after_method(method, hook, opts = {}) return false if method == hook _add_hooked_method(:after, hook, method) original = instance_method(method) @_defining_hook = true define_method(method) do |*args, &block| rtr = original.bind(self).call(*args, &block) if opts[:send_args] method(hook).call(*args) elsif opts[:send_return] || opts[:send_value] result = method(hook).call(rtr) rtr = result if opts[:modify_value] || opts[:modify_return] elsif opts[:send_return_ary] || opts[:send_value_ary] result = method(hook).call(*rtr) rtr = result if opts[:modify_value] || opts[:modify_return] elsif opts[:send_all] result = method(hook).call(args: args, value: rtr, method: method) else method(hook).call end rtr end @_defining_hook = false true end |
#_hook_before_method(method, hook, opts = {}) ⇒ Object
Current opts: send_args - Sends the arguments of the method to the before hook. modify_args - Replaces the original args with the returned value of the send_method - Sends the method name as an argument to the hooked method.
before hook method.
try_first - Sends the args to the desired hook first and if the result
is non-nil, the result is sent instead of calling the hooked
method.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/bblib/core/mixins/hooks.rb', line 89 def _hook_before_method(method, hook, opts = {}) return false if method == hook _add_hooked_method(:before, hook, method) original = instance_method(method) @_defining_hook = true define_method(method) do |*args, &block| if opts[:send_args] || opts[:send_arg] || opts[:modify_args] || opts[:send_method] || opts[:try_first] margs = args margs = [method] + args if opts[:send_method] margs = args + [opts[:add_args]].flatten(1) if opts[:add_args] result = method(hook).call(*margs) return result if result && opts[:try_first] args = result if opts[:modify_args] else method(hook).call end original.bind(self).call(*args, &block) end @_defining_hook = false true end |
#_hook_method(method, force: false) ⇒ Object
34 35 36 37 38 39 40 41 42 |
# File 'lib/bblib/core/mixins/hooks.rb', line 34 def _hook_method(method, force: false) return false if _defining_hook? [:before, :after].each do |hook_type| _hooks[hook_type].find_all { |hook, data| data[:methods].include?(method) }.to_h.each do |hook, data| next if !force && _hooked_methods[hook_type] && _hooked_methods[hook_type][hook] && _hooked_methods[hook_type][hook].include?(method) send("_hook_#{hook_type}_method", method, hook, data[:opts]) end end end |
#_hooked_methods ⇒ Object
67 68 69 |
# File 'lib/bblib/core/mixins/hooks.rb', line 67 def _hooked_methods @_hooked_methods ||= { before: {}, after: {} } end |
#_hooks ⇒ Object
63 64 65 |
# File 'lib/bblib/core/mixins/hooks.rb', line 63 def _hooks @_hooks ||= _superclass_hooks end |
#_superclass_hooks ⇒ Object
def _hook_all
_hooks.each do |type, hooks|
hooks.each do |hook, data|
data[:methods].each do |method|
_hook_method(method)
end
end
end
end
54 55 56 57 58 59 60 61 |
# File 'lib/bblib/core/mixins/hooks.rb', line 54 def _superclass_hooks hooks = { before: {}, after: {} } ancestors.reverse.each do |ancestor| next if ancestor == self hooks = hooks.deep_merge(ancestor.send(:_hooks)) if ancestor.respond_to?(:_hooks) end hooks end |
#method_added(method) ⇒ Object
18 19 20 21 22 23 24 |
# File 'lib/bblib/core/mixins/hooks.rb', line 18 def method_added(method) if _defining_hook? @_defining_hook = false else _hook_method(method) end end |
#singleton_method_added(method) ⇒ Object
26 27 28 29 30 31 32 |
# File 'lib/bblib/core/mixins/hooks.rb', line 26 def singleton_method_added(method) if _defining_hook? @_defining_hook = false else self.singleton_class.send(:_hook_method, method, force: true) if self.singleton_class.respond_to?(:_hook_method) end end |