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
- POST_WORK_EVENTS =
Events fired after
around_execution(work, rollback) finishes. Runtime passes the finalized Signal as the second callback argument so hooks can readreason,cause,metadata,origin, andbacktrace. Set[ :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
-
#key?(event) ⇒ Boolean
Whether a callback is registered under
name. -
#process(event, task, signal = nil) ⇒ 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.
44 45 46 |
# File 'lib/cmdx/callbacks.rb', line 44 def initialize @registry = {} end |
Instance Attribute Details
#registry ⇒ Object (readonly)
Returns the value of attribute registry.
42 43 44 |
# File 'lib/cmdx/callbacks.rb', line 42 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.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/cmdx/callbacks.rb', line 176 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, continuation: cont, &cont) called || raise(CallbackError, <<~MSG.chomp) #{event} callback did not invoke its continuation. See https://drexed.github.io/cmdx/callbacks/#around_execution-the-wrap-the-whole-thing-hook MSG end end.call end |
#count ⇒ Integer
Returns total callbacks across all events.
132 133 134 |
# File 'lib/cmdx/callbacks.rb', line 132 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.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/cmdx/callbacks.rb', line 97 def deregister(event, callable = nil) unless EVENTS.include?(event) raise ArgumentError, <<~MSG.chomp unknown callback event #{event.inspect}, must be one of #{EVENTS.to_a.inspect}. See https://drexed.github.io/cmdx/callbacks/#what-callbacks-exist MSG end 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
122 123 124 |
# File 'lib/cmdx/callbacks.rb', line 122 def empty? registry.empty? end |
#initialize_copy(source) ⇒ void
This method returns an undefined value.
50 51 52 |
# File 'lib/cmdx/callbacks.rb', line 50 def initialize_copy(source) @registry = source.registry.transform_values(&:dup) end |
#key?(event) ⇒ Boolean
Returns whether a callback is registered under name.
117 118 119 |
# File 'lib/cmdx/callbacks.rb', line 117 def key?(event) registry.key?(event) end |
#process(event, task, signal = nil) ⇒ void
This method returns an undefined value.
Fires each callback registered for event against task. Skips any
callback whose :if/:unless gates fail.
Post-work events (POST_WORK_EVENTS) receive the finalized signal as
their second argument (Symbol method, Proc, or #call). Pre-work events
and around_execution omit it.
148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/cmdx/callbacks.rb', line 148 def process(event, task, signal = nil) return if empty? callbacks = registry[event] return if callbacks.nil? || callbacks.empty? post_work = POST_WORK_EVENTS.include?(event) callbacks.each do |callable, | next unless Util.satisfied?([:if], [:unless], task) invoke(callable, task, signal: post_work ? signal : nil) end end |
#register(event, callable = nil, **options, &block) { ... } ⇒ Callbacks
Adds a callback for event.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/cmdx/callbacks.rb', line 66 def register(event, callable = nil, **, &block) callback = callable || block if callable && block raise ArgumentError, "callback: provide either a callable or a block, not both" elsif !callback.is_a?(Symbol) && !callback.respond_to?(:call) raise ArgumentError, <<~MSG.chomp callback must be a Symbol or respond to #call (got #{callback.class}). See https://drexed.github.io/cmdx/callbacks/#how-do-i-register-one MSG elsif !EVENTS.include?(event) raise ArgumentError, <<~MSG.chomp unknown callback event #{event.inspect}, must be one of #{EVENTS.to_a.inspect}. See https://drexed.github.io/cmdx/callbacks/#what-callbacks-exist MSG end (registry[event] ||= []) << [callback, .freeze] self end |
#size ⇒ Integer
Returns number of distinct events with callbacks.
127 128 129 |
# File 'lib/cmdx/callbacks.rb', line 127 def size registry.size end |