Class: Dommy::AbortSignal
- Inherits:
-
Object
- Object
- Dommy::AbortSignal
- Includes:
- Bridge::Methods, EventTarget
- Defined in:
- lib/dommy/event.rb
Overview
‘AbortController` + `AbortSignal` subset. Signal fires an “abort” event and flips `[:aborted]` to true when the controller’s ‘abort()` is called; otherwise it stays inert.
Constant Summary collapse
- NO_REASON =
Sentinel meaning “no reason argument was supplied” — distinct from an explicit ‘null` reason (`abort(null)` keeps reason null, but `abort()` / `abort(undefined)` default to a fresh AbortError).
Object.new
Class Method Summary collapse
-
.abort(*reason) ⇒ Object
Spec: ‘AbortSignal.abort(reason?)` returns a fresh, pre-aborted signal.
-
.any(signals) ⇒ Object
Spec: ‘AbortSignal.any([sig, …])` returns a composite signal that aborts as soon as any of the inputs aborts.
-
.timeout(ms, scheduler: nil) ⇒ Object
Spec: ‘AbortSignal.timeout(ms)` returns a signal that aborts itself after `ms` milliseconds with a `TimeoutError` reason.
Instance Method Summary collapse
- #__internal_mark_aborted__(reason = NO_REASON) ⇒ Object
-
#__internal_schedule_thread_timeout__(ms, reason) ⇒ Object
Background-thread timeout used by ‘AbortSignal.timeout` when no scheduler is provided.
- #__js_call__(method, args) ⇒ Object
- #__js_get__(key) ⇒ Object
-
#__js_set__(key, value) ⇒ Object
‘signal.onabort = fn` is an event-handler IDL attribute: it registers a single “abort” listener (replacing any previous one); null/undefined clears it.
- #aborted? ⇒ Boolean
-
#initialize ⇒ AbortSignal
constructor
A new instance of AbortSignal.
- #reason ⇒ Object
-
#throw_if_aborted ⇒ Object
(also: #throwIfAborted)
Spec: throws ‘signal.reason` if aborted, otherwise no-op.
Methods included from Bridge::Methods
Methods included from EventTarget
#__internal_deliver_event__, #__internal_event_parent__, #add_event_listener, capture_flag, #deliver_at, #dispatch_event, js_truthy?, #remove_event_listener
Constructor Details
#initialize ⇒ AbortSignal
Returns a new instance of AbortSignal.
1038 1039 1040 1041 |
# File 'lib/dommy/event.rb', line 1038 def initialize @aborted = false @reason = nil end |
Class Method Details
.abort(*reason) ⇒ Object
Spec: ‘AbortSignal.abort(reason?)` returns a fresh, pre-aborted signal. Convenient for APIs that need an already-cancelled token.
995 996 997 998 999 |
# File 'lib/dommy/event.rb', line 995 def self.abort(*reason) signal = new signal.__internal_mark_aborted__(*reason) signal end |
.any(signals) ⇒ Object
Spec: ‘AbortSignal.any([sig, …])` returns a composite signal that aborts as soon as any of the inputs aborts. If any input is already aborted, the returned signal is pre-aborted with that input’s reason.
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 |
# File 'lib/dommy/event.rb', line 1022 def self.any(signals) composite = new list = Array(signals).select { |s| s.is_a?(AbortSignal) } already = list.find(&:aborted?) if already composite.__internal_mark_aborted__(already.reason) return composite end list.each do |sig| sig.add_event_listener("abort", proc { composite.__internal_mark_aborted__(sig.reason) }) end composite end |
.timeout(ms, scheduler: nil) ⇒ Object
Spec: ‘AbortSignal.timeout(ms)` returns a signal that aborts itself after `ms` milliseconds with a `TimeoutError` reason. Without a Window/scheduler we fall back to a Thread-based timer so the signal works in vanilla CRuby; embedders that want microtask integration can pass a window via `schedule_via`.
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 |
# File 'lib/dommy/event.rb', line 1006 def self.timeout(ms, scheduler: nil) signal = new reason = DOMException::TimeoutError.new("operation timed out") if scheduler scheduler.set_timeout(proc { signal.__internal_mark_aborted__(reason) }, ms.to_i) else signal.__internal_schedule_thread_timeout__(ms.to_i, reason) end signal end |
Instance Method Details
#__internal_mark_aborted__(reason = NO_REASON) ⇒ Object
1123 1124 1125 1126 1127 1128 1129 1130 |
# File 'lib/dommy/event.rb', line 1123 def __internal_mark_aborted__(reason = NO_REASON) return if @aborted @aborted = true no_reason = reason.equal?(NO_REASON) || (defined?(Bridge::UNDEFINED) && reason.equal?(Bridge::UNDEFINED)) @reason = no_reason ? DOMException::AbortError.new("signal is aborted without reason") : reason dispatch_event(Event.new("abort", "bubbles" => false, "cancelable" => false).__internal_mark_trusted__) end |
#__internal_schedule_thread_timeout__(ms, reason) ⇒ Object
Background-thread timeout used by ‘AbortSignal.timeout` when no scheduler is provided. Kept package-private; tests can also drive the abort manually via `internal_mark_aborted`.
1046 1047 1048 1049 1050 1051 1052 1053 |
# File 'lib/dommy/event.rb', line 1046 def __internal_schedule_thread_timeout__(ms, reason) Thread.new do sleep(ms.to_f / 1000.0) __internal_mark_aborted__(reason) end nil end |
#__js_call__(method, args) ⇒ Object
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 |
# File 'lib/dommy/event.rb', line 1105 def __js_call__(method, args) case method when "addEventListener" add_event_listener(args[0], args[1], args[2]) when "removeEventListener" remove_event_listener(args[0], args[1], args[2]) when "dispatchEvent" dispatch_event(args[0]) when "throwIfAborted" throw_if_aborted end end |
#__js_get__(key) ⇒ Object
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 |
# File 'lib/dommy/event.rb', line 1077 def __js_get__(key) case key when "aborted" @aborted when "reason" # A non-aborted signal's reason is `undefined` (not null); once aborted # it is the abort reason (an explicit value or the default AbortError). @aborted ? @reason : Bridge::UNDEFINED when "onabort" @onabort_handler end end |
#__js_set__(key, value) ⇒ Object
‘signal.onabort = fn` is an event-handler IDL attribute: it registers a single “abort” listener (replacing any previous one); null/undefined clears it. (Setting it after the signal is already aborted never fires.)
1093 1094 1095 1096 1097 1098 1099 1100 1101 |
# File 'lib/dommy/event.rb', line 1093 def __js_set__(key, value) return Bridge::UNHANDLED unless key == "onabort" remove_event_listener("abort", @onabort_handler) if @onabort_handler cleared = value.nil? || (defined?(Bridge::UNDEFINED) && value.equal?(Bridge::UNDEFINED)) @onabort_handler = cleared ? nil : value add_event_listener("abort", @onabort_handler) if @onabort_handler nil end |
#aborted? ⇒ Boolean
1055 1056 1057 |
# File 'lib/dommy/event.rb', line 1055 def aborted? @aborted end |
#reason ⇒ Object
1059 1060 1061 |
# File 'lib/dommy/event.rb', line 1059 def reason @reason end |
#throw_if_aborted ⇒ Object Also known as: throwIfAborted
Spec: throws ‘signal.reason` if aborted, otherwise no-op. Used by consumer code that polls before doing async work.
1065 1066 1067 1068 1069 1070 1071 1072 1073 |
# File 'lib/dommy/event.rb', line 1065 def throw_if_aborted return unless @aborted # An Exception reason (the default AbortError, or an explicit DOMException) # is raised so the bridge tags it as a real JS error; any other reason — a # string, number, or opaque JSValue — is thrown verbatim, identity kept. raise @reason if @reason.is_a?(Exception) raise Bridge::ThrowValue.new(@reason) end |