module

EventHandler

Constants

EMIT_COPY_ON_WRITE = true

Compile-time switch for copy-on-write handler lists.

When true (default), the per-type handler array is immutable: on/off/ remove_all_handlers build a fresh array and swap it in under the lock, rather than mutating the shared array in place. This lets _emit take its snapshot by reading the reference instead of duping on every emit — since emits vastly outnumber subscription changes, this moves the copy off the hot path.

Because the captured array is never mutated, _emit reads its snapshot without taking the lock. The mutex only serializes writers against each other (their dup→mutate→swap is a read-modify-write that would otherwise lose updates).

Correctness holds because nothing published is mutated in place while a concurrent (or reentrant) _emit might be iterating it: a writer always publishes a new array, and an in-flight emit keeps iterating its captured snapshot — the same semantics the previous dup provided. Fibers run in parallel on several threads by default, so the publication is an atomic release store read back with an acquire load: an emit on another thread sees either the previous list or the complete new one.

Set to false to restore the original in-place mutation + per-emit dup; when disabled the copy-on-write code is not generated.

EMIT_SKIP_WHEN_NO_HANDLERS = true

Compile-time switch for the "skip emit when nothing is subscribed" fast path.

When true (default), emit returns immediately if the event has no registered handlers (neither its concrete type nor the catch-all AnyEvent), and the low-level _emit if its own type has none: the handler store is not consulted, (without copy-on-write) the reentrant mutex is not taken, and emit(type, *args) does not build the event object. Matters for emit-heavy workloads (e.g. a UI render loop) with no listeners.

The fast path tests the emitter's subscription bitmask without holding the lock — a benign race already inherent to the snapshot design (a handler added concurrently with an emit isn't guaranteed to observe that emit). Set to false to restore unconditional dispatch; a compile-time constant so the guard generates no code at all when disabled.

Log = ::Log.for("event_handler")

Logger used to report failures that occur while dispatching a handler asynchronously. See Wrapper#call_async for the async error contract.

Per Crystal's Log conventions, emits nothing until the application configures a backend (e.g. Log.setup_from_env). Applications that care about async handler failures should configure one to see these entries.

VERSION = "2.6.1"

Class methods

async=(async : Bool)

Asynchronous execution flag; default false.

Controls whether event handlers execute synchronously one by one, or asynchronously in Fibers.

EventHandler.async? # => false
EventHandler.async = true

Only affects the default; can be overriden per-handler via the async argument when subscribing.

Source
async?

Asynchronous execution flag; default false.

Controls whether event handlers execute synchronously one by one, or asynchronously in Fibers.

EventHandler.async? # => false
EventHandler.async = true

Only affects the default; can be overriden per-handler via the async argument when subscribing.

Source
async_send=(async_send : Bool)

Asynchronous execution flag for #waited events; default false.

Controls whether implicitly created handlers that forward events through channels execute synchronously or asynchronously.

EventHandler.async_send? # => false
EventHandler.async_send = true

Only affects the default; can be overriden per-#wait via async_send.

Source
async_send?

Asynchronous execution flag for #waited events; default false.

Controls whether implicitly created handlers that forward events through channels execute synchronously or asynchronously.

EventHandler.async_send? # => false
EventHandler.async_send = true

Only affects the default; can be overriden per-#wait via async_send.

Source
at_beginning

Default insertion index for a handler inserted at the beginning of the list; default 0.

Rarely needs changing. An index is clamped to the handler list's bounds at insertion (see the at option).

Source
at_beginning=(at_beginning : Int32)

Default insertion index for a handler inserted at the beginning of the list; default 0.

Rarely needs changing. An index is clamped to the handler list's bounds at insertion (see the at option).

Source
at_end

Default insertion index for a handler inserted at the end of the list; default -1.

Rarely needs changing. An index is clamped to the handler list's bounds at insertion (see the at option).

Source
at_end=(at_end : Int32)

Default insertion index for a handler inserted at the end of the list; default -1.

Rarely needs changing. An index is clamped to the handler list's bounds at insertion (see the at option).

Source
emit_on_remove_all=(emit_on_remove_all : Bool)

RemoveHandlerEvent control flag for remove_all_handlers(type) and its off(type) alias; default true.

Controls whether handlers removed by those calls emit a RemoveHandlerEvent. Disabling can make sense at application shutdown when running those handlers no longer matters.

EventHandler.emit_on_remove_all? # => true
EventHandler.emit_on_remove_all = false
Source
emit_on_remove_all?

RemoveHandlerEvent control flag for remove_all_handlers(type) and its off(type) alias; default true.

Controls whether handlers removed by those calls emit a RemoveHandlerEvent. Disabling can make sense at application shutdown when running those handlers no longer matters.

EventHandler.emit_on_remove_all? # => true
EventHandler.emit_on_remove_all = false
Source

Instance methods

emit(type : ::EventHandler::AnyEvent.class, event : EventHandler::AnyEvent)

Emits event of type.

When EMIT_SKIP_WHEN_NO_HANDLERS, emit gains a fast path: if neither this concrete type nor the catch-all AnyEvent has any handler, it returns immediately. It's @[AlwaysInline] so, in the common no-subscriber case, the guard folds into the caller as two bit tests on the emitter's subscription mask — no call into _emit, no lock, no allocation. With the constant off, neither the annotation nor the guard is generated and emit is the original two-line dispatch.

Emits event of type.

When EMIT_SKIP_WHEN_NO_HANDLERS, emit gains a fast path: if neither this concrete type nor the catch-all AnyEvent has any handler, it returns immediately. It's @[AlwaysInline] so, in the common no-subscriber case, the guard folds into the caller as two bit tests on the emitter's subscription mask — no call into _emit, no lock, no allocation. With the constant off, neither the annotation nor the guard is generated and emit is the original two-line dispatch.

Emits event of type.

When EMIT_SKIP_WHEN_NO_HANDLERS, emit gains a fast path: if neither this concrete type nor the catch-all AnyEvent has any handler, it returns immediately. It's @[AlwaysInline] so, in the common no-subscriber case, the guard folds into the caller as two bit tests on the emitter's subscription mask — no call into _emit, no lock, no allocation. With the constant off, neither the annotation nor the guard is generated and emit is the original two-line dispatch.

emit(type : ::EventHandler::Event.class, event : EventHandler::Event)

Fallback of emit(type, event): reached only when event is not a type (every matching pair resolves to a per-type overload).

emit(event : EventHandler::Event)

Emits event of type event.class

Source
emit(type : ::EventHandler::AnyEvent.class, *args) : Nil

Emits event of type.

When EMIT_SKIP_WHEN_NO_HANDLERS, emit gains a fast path: if neither this concrete type nor the catch-all AnyEvent has any handler, it returns immediately. It's @[AlwaysInline] so, in the common no-subscriber case, the guard folds into the caller as two bit tests on the emitter's subscription mask — no call into _emit, no lock, no allocation. With the constant off, neither the annotation nor the guard is generated and emit is the original two-line dispatch.

Returns Nil, unconditionally: with no listener the event object is never built (see below), so there would be nothing to return, and a return type that depends on whether anyone happens to be subscribed is not a usable contract. A caller that needs the emitted object back constructs it itself and uses the emit(type, event) form, which always returns it.

emit(type : ::EventHandler::AddHandlerEvent.class, *args) : Nil

Emits event of type.

When EMIT_SKIP_WHEN_NO_HANDLERS, emit gains a fast path: if neither this concrete type nor the catch-all AnyEvent has any handler, it returns immediately. It's @[AlwaysInline] so, in the common no-subscriber case, the guard folds into the caller as two bit tests on the emitter's subscription mask — no call into _emit, no lock, no allocation. With the constant off, neither the annotation nor the guard is generated and emit is the original two-line dispatch.

Returns Nil, unconditionally: with no listener the event object is never built (see below), so there would be nothing to return, and a return type that depends on whether anyone happens to be subscribed is not a usable contract. A caller that needs the emitted object back constructs it itself and uses the emit(type, event) form, which always returns it.

emit(type : ::EventHandler::RemoveHandlerEvent.class, *args) : Nil

Emits event of type.

When EMIT_SKIP_WHEN_NO_HANDLERS, emit gains a fast path: if neither this concrete type nor the catch-all AnyEvent has any handler, it returns immediately. It's @[AlwaysInline] so, in the common no-subscriber case, the guard folds into the caller as two bit tests on the emitter's subscription mask — no call into _emit, no lock, no allocation. With the constant off, neither the annotation nor the guard is generated and emit is the original two-line dispatch.

Returns Nil, unconditionally: with no listener the event object is never built (see below), so there would be nothing to return, and a return type that depends on whether anyone happens to be subscribed is not a usable contract. A caller that needs the emitted object back constructs it itself and uses the emit(type, event) form, which always returns it.

handlers(type : ::EventHandler::AnyEvent.class)

Returns the list of handlers for event type; an empty array when none is installed.

handlers(type : ::EventHandler::AddHandlerEvent.class)

Returns the list of handlers for event type; an empty array when none is installed.

handlers(type : ::EventHandler::RemoveHandlerEvent.class)

Returns the list of handlers for event type; an empty array when none is installed.

handlers(type : ::EventHandler::Event.class) : EventHandler::ErasedHandlers

Fallback of emit(type, event): reached only when event is not a type (every matching pair resolves to a per-type overload).

The list comes in the erased Wrapper(Proc(Event, Nil)) spelling, the one Subscription#wrapper and the meta events use.

has_handler?(type : ::EventHandler::AnyEvent.class, wrapper : EventHandler::Wrapper(Proc(EventHandler::Event, Nil))) : Bool

Whether wrapper is currently registered for type (compared by identity). This is what Subscription#live? asks.

has_handler?(type : ::EventHandler::AddHandlerEvent.class, wrapper : EventHandler::Wrapper(Proc(EventHandler::Event, Nil))) : Bool

Whether wrapper is currently registered for type (compared by identity). This is what Subscription#live? asks.

has_handler?(type : ::EventHandler::RemoveHandlerEvent.class, wrapper : EventHandler::Wrapper(Proc(EventHandler::Event, Nil))) : Bool

Whether wrapper is currently registered for type (compared by identity). This is what Subscription#live? asks.

has_handlers?(type : ::EventHandler::AnyEvent.class) : Bool

Whether any handler is registered for type. Allocation-free (unlike handlers(type).any?, which dups the COW list).

has_handlers?(type : ::EventHandler::AddHandlerEvent.class) : Bool

Whether any handler is registered for type. Allocation-free (unlike handlers(type).any?, which dups the COW list).

has_handlers?(type : ::EventHandler::RemoveHandlerEvent.class) : Bool

Whether any handler is registered for type. Allocation-free (unlike handlers(type).any?, which dups the COW list).

has_handlers?(type : ::EventHandler::Event.class) : Bool

Fallback of emit(type, event): reached only when event is not a type (every matching pair resolves to a per-type overload).

off(type : ::EventHandler::AnyEvent.class, subscription : EventHandler::Subscription)

Removes the handler behind subscription — the subscription-typed spelling of off(type, wrapper); returns the removed wrapper, or nil when it was no longer registered (or the subscription carries no wrapper).

off(type : ::EventHandler::AnyEvent.class, handler : Proc(EventHandler::AnyEvent, Nil))

Removes handler from the list of handlers for event type.

off(type : ::EventHandler::AnyEvent.class, hash : UInt64)

Removes handler from the list of handlers for event type.

off(type : ::EventHandler::AnyEvent.class, wrapper : EventHandler::Wrapper(Proc(EventHandler::Event, Nil)))

Removes handler from the list of handlers for event type.

off(type : ::EventHandler::AnyEvent.class, at : Int)

Removes handler from the list of handlers for event type.

off(type : ::EventHandler::AnyEvent.class, emit : Bool = ::EventHandler.emit_on_remove_all?)

Removes all handlers for event type.

If emit is false, RemoveHandlerEvents are not emitted.

If emit is true, a RemoveHandlerEvent is emitted once for every distinct Wrapper object removed. See README for details.

emit is restricted to Bool so an argument of any other type is a compile error rather than a silent match of this wipe-all overload.

off(type : ::EventHandler::AddHandlerEvent.class, subscription : EventHandler::Subscription)

Removes the handler behind subscription — the subscription-typed spelling of off(type, wrapper); returns the removed wrapper, or nil when it was no longer registered (or the subscription carries no wrapper).

off(type : ::EventHandler::AddHandlerEvent.class, handler : Proc(EventHandler::AddHandlerEvent, Nil))

Removes handler from the list of handlers for event type.

off(type : ::EventHandler::AddHandlerEvent.class, hash : UInt64)

Removes handler from the list of handlers for event type.

Removes handler from the list of handlers for event type.

off(type : ::EventHandler::AddHandlerEvent.class, at : Int)

Removes handler from the list of handlers for event type.

off(type : ::EventHandler::AddHandlerEvent.class, emit : Bool = ::EventHandler.emit_on_remove_all?)

Removes all handlers for event type.

If emit is false, RemoveHandlerEvents are not emitted.

If emit is true, a RemoveHandlerEvent is emitted once for every distinct Wrapper object removed. See README for details.

emit is restricted to Bool so an argument of any other type is a compile error rather than a silent match of this wipe-all overload.

Removes the handler behind subscription — the subscription-typed spelling of off(type, wrapper); returns the removed wrapper, or nil when it was no longer registered (or the subscription carries no wrapper).

off(type : ::EventHandler::RemoveHandlerEvent.class, handler : Proc(EventHandler::RemoveHandlerEvent, Nil))

Removes handler from the list of handlers for event type.

off(type : ::EventHandler::RemoveHandlerEvent.class, hash : UInt64)

Removes handler from the list of handlers for event type.

Removes handler from the list of handlers for event type.

off(type : ::EventHandler::RemoveHandlerEvent.class, at : Int)

Removes handler from the list of handlers for event type.

off(type : ::EventHandler::RemoveHandlerEvent.class, emit : Bool = ::EventHandler.emit_on_remove_all?)

Removes all handlers for event type.

If emit is false, RemoveHandlerEvents are not emitted.

If emit is true, a RemoveHandlerEvent is emitted once for every distinct Wrapper object removed. See README for details.

emit is restricted to Bool so an argument of any other type is a compile error rather than a silent match of this wipe-all overload.

off(type : ::EventHandler::Event.class, wrapper : EventHandler::Wrapper(Proc(EventHandler::Event, Nil))) : EventHandler::Wrapper(Proc(EventHandler::Event, Nil)) | Nil

Fallback of emit(type, event): reached only when event is not a type (every matching pair resolves to a per-type overload).

on(type : ::EventHandler::AnyEvent.class, handler : Proc(EventHandler::AnyEvent, Nil), once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds handler to the list of handlers for event type.

Returns an EventHandler::Subscription — a self-contained disconnect handle: sub.off removes exactly this handler, with no need to restate the event type or hold the Wrapper (cf. Qt's QMetaObject::Connection). The Wrapper itself still flows to AddHandlerEvent/RemoveHandlerEvent listeners, and the off(type, handler/hash/at) forms keep working for callers that kept those instead.

Re-registers the Wrapper behind subscription — the subscription-typed spelling of on(type, wrapper). Raises ArgumentError when the subscription carries no wrapper (see Subscription#wrapper).

on(type : ::EventHandler::AnyEvent.class, *, once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end, &handler : EventHandler::AnyEvent -> Nil) : EventHandler::Subscription

Removes the handler behind subscription — the subscription-typed spelling of off(type, wrapper); returns the removed wrapper, or nil when it was no longer registered (or the subscription carries no wrapper).

Adds wrapper (one on returned via Subscription#wrapper, one a meta event carried, or one built by hand) to the handlers for type, with the once/async/at settings it carries. Raises ArgumentError if the wrapper was built for an event its handler cannot take, i.e. one that is not type or an ancestor of it.

on(type : ::EventHandler::AnyEvent.class, channel : Channel(EventHandler::AnyEvent), once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds an autogenerated handler which sends emitted events to channel

on(type : ::EventHandler::AddHandlerEvent.class, handler : Proc(EventHandler::AddHandlerEvent, Nil), once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds handler to the list of handlers for event type.

Returns an EventHandler::Subscription — a self-contained disconnect handle: sub.off removes exactly this handler, with no need to restate the event type or hold the Wrapper (cf. Qt's QMetaObject::Connection). The Wrapper itself still flows to AddHandlerEvent/RemoveHandlerEvent listeners, and the off(type, handler/hash/at) forms keep working for callers that kept those instead.

Re-registers the Wrapper behind subscription — the subscription-typed spelling of on(type, wrapper). Raises ArgumentError when the subscription carries no wrapper (see Subscription#wrapper).

on(type : ::EventHandler::AddHandlerEvent.class, *, once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end, &handler : EventHandler::AddHandlerEvent -> Nil) : EventHandler::Subscription

Removes the handler behind subscription — the subscription-typed spelling of off(type, wrapper); returns the removed wrapper, or nil when it was no longer registered (or the subscription carries no wrapper).

Adds wrapper (one on returned via Subscription#wrapper, one a meta event carried, or one built by hand) to the handlers for type, with the once/async/at settings it carries. Raises ArgumentError if the wrapper was built for an event its handler cannot take, i.e. one that is not type or an ancestor of it.

on(type : ::EventHandler::AddHandlerEvent.class, channel : Channel(EventHandler::AddHandlerEvent), once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds an autogenerated handler which sends emitted events to channel

on(type : ::EventHandler::RemoveHandlerEvent.class, handler : Proc(EventHandler::RemoveHandlerEvent, Nil), once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds handler to the list of handlers for event type.

Returns an EventHandler::Subscription — a self-contained disconnect handle: sub.off removes exactly this handler, with no need to restate the event type or hold the Wrapper (cf. Qt's QMetaObject::Connection). The Wrapper itself still flows to AddHandlerEvent/RemoveHandlerEvent listeners, and the off(type, handler/hash/at) forms keep working for callers that kept those instead.

Re-registers the Wrapper behind subscription — the subscription-typed spelling of on(type, wrapper). Raises ArgumentError when the subscription carries no wrapper (see Subscription#wrapper).

on(type : ::EventHandler::RemoveHandlerEvent.class, *, once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end, &handler : EventHandler::RemoveHandlerEvent -> Nil) : EventHandler::Subscription

Removes the handler behind subscription — the subscription-typed spelling of off(type, wrapper); returns the removed wrapper, or nil when it was no longer registered (or the subscription carries no wrapper).

Adds wrapper (one on returned via Subscription#wrapper, one a meta event carried, or one built by hand) to the handlers for type, with the once/async/at settings it carries. Raises ArgumentError if the wrapper was built for an event its handler cannot take, i.e. one that is not type or an ancestor of it.

on(type : ::EventHandler::RemoveHandlerEvent.class, channel : Channel(EventHandler::RemoveHandlerEvent), once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds an autogenerated handler which sends emitted events to channel

Fallback of emit(type, event): reached only when event is not a type (every matching pair resolves to a per-type overload).

on_add_handler_event(*, once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end, &handler : EventHandler::AddHandlerEvent -> Nil) : EventHandler::Subscription

Per-event subscribe sugar, named after the event itself (the underscored last path component of the event class: event Clicked also defines on_clicked(&) on every emitter). Equivalent to on(::EventHandler::AddHandlerEvent) { |e| ... }; returns the EventHandler::Subscription (see on). Emitters may shadow a generated method with a richer hand-written adapter (one yielding the event's payload instead of the event).

Skipped for an event nested inside another event class (e.g. a per-key KeyPress::<member> family): the last name component alone is ambiguous there — it can collide with an unrelated top-level event of the same name — and such families are typically generated and huge. Subscribe to those with the explicit on(Type) { } form.

Also skipped when two event classes in different namespaces share a last name component (::Clicked and Foo::Clicked): both would define the same method and the later one would silently win. Options are keyword-only (bare *, like the block overload of on): with untyped positionals an emitter's own same-name sugar taking positional args (e.g. Crysterm's on_key('q', :escape)) would bind them to once/async here and fail deep in internal_insert instead of resolving to that overload.

on_any_event(*, once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end, &handler : EventHandler::AnyEvent -> Nil) : EventHandler::Subscription

Per-event subscribe sugar, named after the event itself (the underscored last path component of the event class: event Clicked also defines on_clicked(&) on every emitter). Equivalent to on(::EventHandler::AnyEvent) { |e| ... }; returns the EventHandler::Subscription (see on). Emitters may shadow a generated method with a richer hand-written adapter (one yielding the event's payload instead of the event).

Skipped for an event nested inside another event class (e.g. a per-key KeyPress::<member> family): the last name component alone is ambiguous there — it can collide with an unrelated top-level event of the same name — and such families are typically generated and huge. Subscribe to those with the explicit on(Type) { } form.

Also skipped when two event classes in different namespaces share a last name component (::Clicked and Foo::Clicked): both would define the same method and the later one would silently win. Options are keyword-only (bare *, like the block overload of on): with untyped positionals an emitter's own same-name sugar taking positional args (e.g. Crysterm's on_key('q', :escape)) would bind them to once/async here and fail deep in internal_insert instead of resolving to that overload.

on_remove_handler_event(*, once = false, async = ::EventHandler.async?, at = ::EventHandler.at_end, &handler : EventHandler::RemoveHandlerEvent -> Nil) : EventHandler::Subscription

Per-event subscribe sugar, named after the event itself (the underscored last path component of the event class: event Clicked also defines on_clicked(&) on every emitter). Equivalent to on(::EventHandler::RemoveHandlerEvent) { |e| ... }; returns the EventHandler::Subscription (see on). Emitters may shadow a generated method with a richer hand-written adapter (one yielding the event's payload instead of the event).

Skipped for an event nested inside another event class (e.g. a per-key KeyPress::<member> family): the last name component alone is ambiguous there — it can collide with an unrelated top-level event of the same name — and such families are typically generated and huge. Subscribe to those with the explicit on(Type) { } form.

Also skipped when two event classes in different namespaces share a last name component (::Clicked and Foo::Clicked): both would define the same method and the later one would silently win. Options are keyword-only (bare *, like the block overload of on): with untyped positionals an emitter's own same-name sugar taking positional args (e.g. Crysterm's on_key('q', :escape)) would bind them to once/async here and fail deep in internal_insert instead of resolving to that overload.

once(type : ::EventHandler::AnyEvent.class, handler : Proc(EventHandler::AnyEvent, Nil), async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds handler to the list of handlers for event type; removed automatically after it triggers once. Returns an EventHandler::Subscription (see on); its #off is a no-op after the handler has auto-fired away.

Equivalent to on with argument once.

once(type : ::EventHandler::AnyEvent.class, *, async = ::EventHandler.async?, at = ::EventHandler.at_end, &handler : EventHandler::AnyEvent -> Nil) : EventHandler::Subscription

Adds handler to the list of handlers for event type; removed automatically after it triggers once. Returns an EventHandler::Subscription (see on); its #off is a no-op after the handler has auto-fired away.

Equivalent to on with argument once.

Options are keyword-only, as in the block form of on.

once(type : ::EventHandler::AnyEvent.class, channel : Channel(EventHandler::AnyEvent), async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds an autogenerated handler which sends emitted events to channel; removed automatically after it triggers once.

Equivalent to on with argument once.

once(type : ::EventHandler::AddHandlerEvent.class, handler : Proc(EventHandler::AddHandlerEvent, Nil), async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds handler to the list of handlers for event type; removed automatically after it triggers once. Returns an EventHandler::Subscription (see on); its #off is a no-op after the handler has auto-fired away.

Equivalent to on with argument once.

once(type : ::EventHandler::AddHandlerEvent.class, *, async = ::EventHandler.async?, at = ::EventHandler.at_end, &handler : EventHandler::AddHandlerEvent -> Nil) : EventHandler::Subscription

Adds handler to the list of handlers for event type; removed automatically after it triggers once. Returns an EventHandler::Subscription (see on); its #off is a no-op after the handler has auto-fired away.

Equivalent to on with argument once.

Options are keyword-only, as in the block form of on.

once(type : ::EventHandler::AddHandlerEvent.class, channel : Channel(EventHandler::AddHandlerEvent), async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds an autogenerated handler which sends emitted events to channel; removed automatically after it triggers once.

Equivalent to on with argument once.

once(type : ::EventHandler::RemoveHandlerEvent.class, handler : Proc(EventHandler::RemoveHandlerEvent, Nil), async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds handler to the list of handlers for event type; removed automatically after it triggers once. Returns an EventHandler::Subscription (see on); its #off is a no-op after the handler has auto-fired away.

Equivalent to on with argument once.

once(type : ::EventHandler::RemoveHandlerEvent.class, *, async = ::EventHandler.async?, at = ::EventHandler.at_end, &handler : EventHandler::RemoveHandlerEvent -> Nil) : EventHandler::Subscription

Adds handler to the list of handlers for event type; removed automatically after it triggers once. Returns an EventHandler::Subscription (see on); its #off is a no-op after the handler has auto-fired away.

Equivalent to on with argument once.

Options are keyword-only, as in the block form of on.

once(type : ::EventHandler::RemoveHandlerEvent.class, channel : Channel(EventHandler::RemoveHandlerEvent), async = ::EventHandler.async?, at = ::EventHandler.at_end) : EventHandler::Subscription

Adds an autogenerated handler which sends emitted events to channel; removed automatically after it triggers once.

Equivalent to on with argument once.

remove_all_handlers(type : ::EventHandler::AnyEvent.class, emit : Bool = ::EventHandler.emit_on_remove_all?)

Removes all handlers for event type.

If emit is false, RemoveHandlerEvents are not emitted.

If emit is true, a RemoveHandlerEvent is emitted once for every distinct Wrapper object removed. See README for details.

remove_all_handlers(type : ::EventHandler::AddHandlerEvent.class, emit : Bool = ::EventHandler.emit_on_remove_all?)

Removes all handlers for event type.

If emit is false, RemoveHandlerEvents are not emitted.

If emit is true, a RemoveHandlerEvent is emitted once for every distinct Wrapper object removed. See README for details.

remove_all_handlers(type : ::EventHandler::RemoveHandlerEvent.class, emit : Bool = ::EventHandler.emit_on_remove_all?)

Removes all handlers for event type.

If emit is false, RemoveHandlerEvents are not emitted.

If emit is true, a RemoveHandlerEvent is emitted once for every distinct Wrapper object removed. See README for details.

remove_all_handlers(emit : Bool = false) : Nil

Removes every handler this emitter carries, for every event type — the whole-object counterpart of remove_all_handlers(type). Use it when the emitter itself is being torn down and nothing subscribed to it should keep running (or keep the emitter, and whatever its handlers captured, alive).

Handlers this object registered on other emitters are unaffected — nothing links them back here. Cancel those through the Subscription/Subscriptions they returned.

emit controls RemoveHandlerEvent emission as in remove_all_handlers(type, emit); it defaults to off here, since a torn-down emitter has no use for the notifications. When on, the RemoveHandlerEvent listeners present at the call see every other type's removals first, and are then removed last — with nothing left to announce that to, exactly as remove_all_handlers(RemoveHandlerEvent, true) behaves.

Without announcements this is a single lock, whatever the number of event types: the store is detached and the subscription mask zeroed in one pass.

wait(type : ::EventHandler::AnyEvent.class, handler : Proc(EventHandler::AnyEvent, Nil) | Nil, async = ::EventHandler.async?, at = ::EventHandler.at_end, async_send = ::EventHandler.async_send?)

Blocks until event type is emitted and executes handler.

handler may be nil, in which case wait blocks until the event arrives and returns it without running any handler.

The wait ends only when the event is emitted: if its implicit handler is removed first (remove_all_handlers, off(type)), the waiting fiber stays parked. Tear down an emitter that may have waiters only after they have been released.

wait(type : ::EventHandler::AnyEvent.class, *, async = ::EventHandler.async?, at = ::EventHandler.at_end, async_send = ::EventHandler.async_send?, &handler : EventHandler::AnyEvent -> Nil)

Blocks until event type is emitted and executes handler.

handler may be nil, in which case wait blocks until the event arrives and returns it without running any handler.

The wait ends only when the event is emitted: if its implicit handler is removed first (remove_all_handlers, off(type)), the waiting fiber stays parked. Tear down an emitter that may have waiters only after they have been released.

Options are keyword-only, as in the block form of on: positionally, the second argument of the handler-less wait below is async_send while here it would be async, an easy mix-up.

wait(type : ::EventHandler::AnyEvent.class, async_send = ::EventHandler.async_send?, at = ::EventHandler.at_end)

Blocks until event type is emitted and returns emitted event.

wait(type : ::EventHandler::AddHandlerEvent.class, handler : Proc(EventHandler::AddHandlerEvent, Nil) | Nil, async = ::EventHandler.async?, at = ::EventHandler.at_end, async_send = ::EventHandler.async_send?)

Blocks until event type is emitted and executes handler.

handler may be nil, in which case wait blocks until the event arrives and returns it without running any handler.

The wait ends only when the event is emitted: if its implicit handler is removed first (remove_all_handlers, off(type)), the waiting fiber stays parked. Tear down an emitter that may have waiters only after they have been released.

wait(type : ::EventHandler::AddHandlerEvent.class, *, async = ::EventHandler.async?, at = ::EventHandler.at_end, async_send = ::EventHandler.async_send?, &handler : EventHandler::AddHandlerEvent -> Nil)

Blocks until event type is emitted and executes handler.

handler may be nil, in which case wait blocks until the event arrives and returns it without running any handler.

The wait ends only when the event is emitted: if its implicit handler is removed first (remove_all_handlers, off(type)), the waiting fiber stays parked. Tear down an emitter that may have waiters only after they have been released.

Options are keyword-only, as in the block form of on: positionally, the second argument of the handler-less wait below is async_send while here it would be async, an easy mix-up.

wait(type : ::EventHandler::AddHandlerEvent.class, async_send = ::EventHandler.async_send?, at = ::EventHandler.at_end)

Blocks until event type is emitted and returns emitted event.

wait(type : ::EventHandler::RemoveHandlerEvent.class, handler : Proc(EventHandler::RemoveHandlerEvent, Nil) | Nil, async = ::EventHandler.async?, at = ::EventHandler.at_end, async_send = ::EventHandler.async_send?)

Blocks until event type is emitted and executes handler.

handler may be nil, in which case wait blocks until the event arrives and returns it without running any handler.

The wait ends only when the event is emitted: if its implicit handler is removed first (remove_all_handlers, off(type)), the waiting fiber stays parked. Tear down an emitter that may have waiters only after they have been released.

wait(type : ::EventHandler::RemoveHandlerEvent.class, *, async = ::EventHandler.async?, at = ::EventHandler.at_end, async_send = ::EventHandler.async_send?, &handler : EventHandler::RemoveHandlerEvent -> Nil)

Blocks until event type is emitted and executes handler.

handler may be nil, in which case wait blocks until the event arrives and returns it without running any handler.

The wait ends only when the event is emitted: if its implicit handler is removed first (remove_all_handlers, off(type)), the waiting fiber stays parked. Tear down an emitter that may have waiters only after they have been released.

Options are keyword-only, as in the block form of on: positionally, the second argument of the handler-less wait below is async_send while here it would be async, an easy mix-up.

wait(type : ::EventHandler::RemoveHandlerEvent.class, async_send = ::EventHandler.async_send?, at = ::EventHandler.at_end)

Blocks until event type is emitted and returns emitted event.

Macros

event(e, *args, &block)

Creates events in a single line; every event is a class inheriting from EventHandler::Event.

Since events are classes, they can also be created manually. See EventHandler::Event for more details.

event MouseClick, x : ::Int32, y : ::Int32

A block, if given, becomes part of the class body:

event MouseClick, x : ::Int32, y : ::Int32 do
  def origin?
    x == 0 && y == 0
  end
end
Source

Nested types