Class: Tina4::Events
- Inherits:
-
Object
- Object
- Tina4::Events
- Defined in:
- lib/tina4/events.rb
Class Method Summary collapse
-
.clear ⇒ Object
Remove all listeners for all events.
-
.emit(event, *args, strict: false) ⇒ Object
Fire an event synchronously.
-
.emit_async(event, *args, strict: false) ⇒ Object
Fire an event asynchronously.
-
.events ⇒ Object
List all registered event names.
-
.listeners(event) ⇒ Object
Get all listener callbacks for an event (in priority order).
-
.off(event, callback = nil) ⇒ Object
Remove a specific listener, or all listeners for an event.
-
.on(event, priority: 0, &block) ⇒ Object
Register a listener for an event.
-
.once(event, priority: 0, &block) ⇒ Object
Register a listener that fires only once then auto-removes.
Class Method Details
.clear ⇒ Object
Remove all listeners for all events.
129 130 131 |
# File 'lib/tina4/events.rb', line 129 def clear @listeners.clear end |
.emit(event, *args, strict: false) ⇒ Object
Fire an event synchronously. Returns array of listener results.
results = Tina4::Events.emit("user.created", user_data)
Listener isolation (visible-but-resilient): each listener is called inside a rescue so ONE throwing listener never aborts the rest of the emit. A failed listener is LOGGED (never silent) and contributes a nil slot, so N listeners always yield N results in priority order. Pass strict: true to RE-RAISE on the first listener error instead of isolating (later listeners then do NOT run).
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/tina4/events.rb', line 69 def emit(event, *args, strict: false) entries = @listeners[event].dup results = [] entries.each do |entry| # Remove one-time listeners before calling so re-entrant emits are # safe AND so the one-shot is gone before any throw — cleanup stays # correct under isolation. @listeners[event].delete(entry) if entry[:once] begin results << entry[:callback].call(*args) rescue StandardError, ScriptError => error raise if strict log_listener_error(event, error) results << nil end end results end |
.emit_async(event, *args, strict: false) ⇒ Object
Fire an event asynchronously. Each listener runs in its own thread.
Tina4::Events.emit_async("user.created", user_data)
Listener isolation: each threaded listener is wrapped so one rejection never aborts the others. A failed listener is LOGGED (never silent). Pass strict: true to RE-RAISE the first listener error on the main thread (the thread that raised aborts on join) instead of isolating.
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/tina4/events.rb', line 107 def emit_async(event, *args, strict: false) return unless @listeners&.key?(event) @listeners[event].sort_by { |l| -(l[:priority] || 0) }.map do |listener| Thread.new do # In strict mode the error is re-raised to surface on #join; mute # the per-thread auto-report so the deliberate raise doesn't spam # stderr (the caller still sees it via join). Thread.current.report_on_exception = false if strict begin listener[:callback].call(*args) rescue StandardError, ScriptError => error raise if strict log_listener_error(event, error) nil end end end end |
.events ⇒ Object
List all registered event names.
95 96 97 |
# File 'lib/tina4/events.rb', line 95 def events @listeners.keys end |
.listeners(event) ⇒ Object
Get all listener callbacks for an event (in priority order).
90 91 92 |
# File 'lib/tina4/events.rb', line 90 def listeners(event) @listeners[event].map { |entry| entry[:callback] } end |
.off(event, callback = nil) ⇒ Object
51 52 53 54 55 56 57 |
# File 'lib/tina4/events.rb', line 51 def off(event, callback = nil) if callback.nil? @listeners.delete(event) else @listeners[event].reject! { |entry| entry[:callback] == callback } end end |
.on(event, priority: 0, &block) ⇒ Object
Register a listener for an event.
Tina4::Events.on("user.created") { |user| ... }
Tina4::Events.on("user.created", priority: 10) { |user| ... }
Higher priority runs first.
26 27 28 29 30 31 32 |
# File 'lib/tina4/events.rb', line 26 def on(event, priority: 0, &block) raise ArgumentError, "block required" unless block_given? @listeners[event] << { priority: priority, callback: block, once: false } @listeners[event].sort_by! { |entry| -entry[:priority] } block end |
.once(event, priority: 0, &block) ⇒ Object
38 39 40 41 42 43 44 |
# File 'lib/tina4/events.rb', line 38 def once(event, priority: 0, &block) raise ArgumentError, "block required" unless block_given? @listeners[event] << { priority: priority, callback: block, once: true } @listeners[event].sort_by! { |entry| -entry[:priority] } block end |