Class: CMDx::Callbacks
- Inherits:
-
Object
- Object
- CMDx::Callbacks
- Defined in:
- lib/cmdx/callbacks.rb
Overview
Registry of lifecycle callbacks invoked by Runtime. Callbacks can be
method names (Symbols dispatched via task.send), blocks/Procs
(instance_exec'd on the task), or arbitrary #call objects.
Each registration may carry :if / :unless gates (Symbol, Proc, or
any #call-able). Gates are evaluated against the task before the
callback is invoked; non-passing gates skip the callback silently.
Constant Summary collapse
- EVENTS =
Callback event names Runtime dispatches.
Set[ :before_validation, :before_execution, :around_execution, :after_execution, :on_complete, :on_interrupted, :on_success, :on_skipped, :on_failed, :on_ok, :on_ko ].freeze
Instance Attribute Summary collapse
-
#registry ⇒ Object
readonly
Returns the value of attribute registry.
Instance Method Summary collapse
-
#around(event, task, &body) { ... } ⇒ void
Wraps
blockwith every callback registered foreventas a nested chain (outer-first by declaration order). -
#count ⇒ Integer
Total callbacks across all events.
-
#deregister(event, callable = nil) ⇒ Callbacks
Drops callbacks registered for
event. - #empty? ⇒ Boolean
-
#initialize ⇒ Callbacks
constructor
A new instance of Callbacks.
- #initialize_copy(source) ⇒ void
-
#process(event, task) ⇒ void
Fires each callback registered for
eventagainsttask. -
#register(event, callable = nil, **options, &block) { ... } ⇒ Callbacks
Adds a callback for
event. -
#size ⇒ Integer
Number of distinct events with callbacks.
Constructor Details
#initialize ⇒ Callbacks
Returns a new instance of Callbacks.
30 31 32 |
# File 'lib/cmdx/callbacks.rb', line 30 def initialize @registry = {} end |
Instance Attribute Details
#registry ⇒ Object (readonly)
Returns the value of attribute registry.
28 29 30 |
# File 'lib/cmdx/callbacks.rb', line 28 def registry @registry end |
Instance Method Details
#around(event, task, &body) { ... } ⇒ void
This method returns an undefined value.
Wraps block with every callback registered for event as a nested
chain (outer-first by declaration order). Each callback receives a
continuation it must invoke exactly once: Symbol callbacks get it as
their block (use yield); Procs/blocks are instance_exec'd on the
task with (task, continuation); arbitrary callables receive
(task, continuation). Gates skip individual links silently while
still running the body.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/cmdx/callbacks.rb', line 137 def around(event, task, &body) callbacks = registry[event] return yield if callbacks.nil? || callbacks.empty? callbacks.reverse_each.reduce(body) do |succ, (callable, )| lambda do next succ.call unless Util.satisfied?([:if], [:unless], task) called = false cont = lambda do called = true succ.call end invoke(callable, task, cont, &cont) called || raise(CallbackError, "#{event} callback did not invoke its continuation") end end.call end |
#count ⇒ Integer
Returns total callbacks across all events.
101 102 103 |
# File 'lib/cmdx/callbacks.rb', line 101 def count registry.each_value.sum(&:size) end |
#deregister(event, callable = nil) ⇒ Callbacks
Drops callbacks registered for event. With no callable, removes
every callback for event. With a callable, removes only the
entries whose callback matches callable by == (works for Symbol
method names, classes/modules, and any callable held by reference).
When the last entry for event is removed, the key itself is dropped.
77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/cmdx/callbacks.rb', line 77 def deregister(event, callable = nil) raise ArgumentError, "unknown event #{event.inspect}, must be one of #{EVENTS.join(', ')}" unless EVENTS.include?(event) if callable.nil? registry.delete(event) elsif (entries = registry[event]) entries.reject! { |cb, _opts| cb == callable } registry.delete(event) if entries.empty? end self end |
#empty? ⇒ Boolean
91 92 93 |
# File 'lib/cmdx/callbacks.rb', line 91 def empty? registry.empty? end |
#initialize_copy(source) ⇒ void
This method returns an undefined value.
36 37 38 |
# File 'lib/cmdx/callbacks.rb', line 36 def initialize_copy(source) @registry = source.registry.transform_values(&:dup) end |
#process(event, task) ⇒ void
This method returns an undefined value.
Fires each callback registered for event against task. Skips any
callback whose :if/:unless gates fail.
112 113 114 115 116 117 118 119 120 121 |
# File 'lib/cmdx/callbacks.rb', line 112 def process(event, task) callbacks = registry[event] return if callbacks.nil? || callbacks.empty? callbacks.each do |callable, | next unless Util.satisfied?([:if], [:unless], task) invoke(callable, task) end end |
#register(event, callable = nil, **options, &block) { ... } ⇒ Callbacks
Adds a callback for event.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/cmdx/callbacks.rb', line 52 def register(event, callable = nil, **, &block) callback = callable || block if callable && block raise ArgumentError, "provide either a callable or a block, not both" elsif !callback.is_a?(Symbol) && !callback.respond_to?(:call) raise ArgumentError, "callback must be a Symbol or respond to #call" elsif !EVENTS.include?(event) raise ArgumentError, "unknown event #{event.inspect}, must be one of #{EVENTS.join(', ')}" end (registry[event] ||= []) << [callback, .freeze] self end |
#size ⇒ Integer
Returns number of distinct events with callbacks.
96 97 98 |
# File 'lib/cmdx/callbacks.rb', line 96 def size registry.size end |