Class: Zenrows::Hooks
- Inherits:
-
Object
- Object
- Zenrows::Hooks
- Includes:
- MonitorMixin
- Defined in:
- lib/zenrows/hooks.rb,
lib/zenrows/hooks/context.rb,
lib/zenrows/hooks/log_subscriber.rb
Overview
Thread-safe hook registry for request lifecycle events
Manages registration and execution of callbacks for HTTP request events. Supports both block-based callbacks and subscriber objects.
Defined Under Namespace
Classes: Context, LogSubscriber
Constant Summary collapse
- EVENTS =
Available hook events
i[before_request after_request on_response on_error around_request].freeze
Instance Method Summary collapse
-
#add_subscriber(subscriber) ⇒ self
Add a subscriber object that responds to hook methods.
-
#callbacks_for(event) ⇒ Array
protected
Get callbacks for a specific event (for merging).
-
#dup ⇒ Hooks
Duplicate the hooks registry.
-
#empty? ⇒ Boolean
Check if any hooks are registered.
-
#initialize ⇒ Hooks
constructor
A new instance of Hooks.
-
#merge(other) ⇒ self
Merge hooks from another registry.
-
#register(event, callable = nil) { ... } ⇒ self
Register a callback for an event.
-
#run(event, *args) ⇒ void
Run callbacks for an event.
-
#run_around(context) { ... } ⇒ Object
Run around callbacks (wrapping).
-
#subscribers_list ⇒ Array
protected
Get subscribers list (for merging).
Constructor Details
#initialize ⇒ Hooks
Returns a new instance of Hooks.
32 33 34 35 36 |
# File 'lib/zenrows/hooks.rb', line 32 def initialize super # Initialize MonitorMixin @callbacks = Hash.new { |h, k| h[k] = [] } @subscribers = [] end |
Instance Method Details
#add_subscriber(subscriber) ⇒ self
Add a subscriber object that responds to hook methods
Subscriber objects can implement any of the hook methods:
- before_request(context)
- after_request(context)
- on_response(response, context)
- on_error(error, context)
- around_request(context, &block)
79 80 81 82 83 84 85 |
# File 'lib/zenrows/hooks.rb', line 79 def add_subscriber(subscriber) unless EVENTS.any? { |e| subscriber.respond_to?(e) } warn "ZenRows: Subscriber #{subscriber.class} doesn't respond to any hook events" end synchronize { @subscribers << subscriber } self end |
#callbacks_for(event) ⇒ Array (protected)
Get callbacks for a specific event (for merging)
172 173 174 |
# File 'lib/zenrows/hooks.rb', line 172 def callbacks_for(event) synchronize { @callbacks[event].dup } end |
#dup ⇒ Hooks
Duplicate the hooks registry
157 158 159 160 161 162 163 164 |
# File 'lib/zenrows/hooks.rb', line 157 def dup copy = Hooks.new synchronize do EVENTS.each { |e| @callbacks[e].each { |h| copy.register(e, h) } } @subscribers.each { |s| copy.add_subscriber(s) } end copy end |
#empty? ⇒ Boolean
Check if any hooks are registered
132 133 134 |
# File 'lib/zenrows/hooks.rb', line 132 def empty? synchronize { @callbacks.values.all?(&:empty?) && @subscribers.empty? } end |
#merge(other) ⇒ self
Merge hooks from another registry
Used for per-client hooks that inherit from global hooks.
142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/zenrows/hooks.rb', line 142 def merge(other) return self unless other synchronize do EVENTS.each do |event| @callbacks[event].concat(other.callbacks_for(event)) end @subscribers.concat(other.subscribers_list) end self end |
#register(event, callable = nil) { ... } ⇒ self
Register a callback for an event
51 52 53 54 55 56 57 58 |
# File 'lib/zenrows/hooks.rb', line 51 def register(event, callable = nil, &block) validate_event!(event) handler = callable || block raise ArgumentError, "Handler must respond to #call" unless handler.respond_to?(:call) synchronize { @callbacks[event] << handler } self end |
#run(event, *args) ⇒ void
This method returns an undefined value.
Run callbacks for an event
92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/zenrows/hooks.rb', line 92 def run(event, *args) handlers, subscribers = synchronize do [@callbacks[event].dup, @subscribers.dup] end # Run registered callbacks handlers.each { |h| h.call(*args) } # Run subscriber methods subscribers.each do |sub| sub.public_send(event, *args) if sub.respond_to?(event) end end |
#run_around(context) { ... } ⇒ Object
Run around callbacks (wrapping)
Executes a chain of around handlers, each wrapping the next. If no around handlers exist, simply yields to the block.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/zenrows/hooks.rb', line 114 def run_around(context, &block) handlers, subscribers = synchronize do [@callbacks[:around_request].dup, @subscribers.dup] end # Build chain of around handlers chain = handlers + subscribers.select { |s| s.respond_to?(:around_request) } if chain.empty? block.call else execute_chain(chain, context, &block) end end |
#subscribers_list ⇒ Array (protected)
Get subscribers list (for merging)
179 180 181 |
# File 'lib/zenrows/hooks.rb', line 179 def subscribers_list synchronize { @subscribers.dup } end |