Search documentation of mob

# Mob.Event (mob v0.6.18)

Copy Markdown View Source

The unified event emission API for Mob.

See `guides/event_model.md` for the full event model.

Two responsibilities:

1. Emit — given an `%Address{}`, an event atom, and a payload, deliver the canonical envelope `{:mob_event, addr, event, payload}` to the right pid (resolving in-tree or external targets).

2. Match — small helpers (`is_event?/1`, `match_address?/2`) for handler code that wants to filter incoming events by address fields.

This module is the single doorway between native event sources and user-level handler code. Every emitter (taps, gestures, lifecycle, custom components) eventually calls `Mob.Event.emit/4` (or `dispatch/4`, for pre-resolved pids).

## Summary

### Types

envelope()

The shape of every event message delivered to a handler.

### Functions

dispatch(pid, addr, event, payload)

Send the event to an already-resolved pid.

emit(addr, event, payload, target, scope)

Resolve `target` and deliver the event.

is_event?(arg1)

True if `msg` matches the canonical event envelope shape.

match_address?(addr, filters)

True if `addr` matches all the given filters.

send_test(pid, screen, widget, id, event, payload \\ nil, opts \\ [])

Synthesize an event delivery to `pid`. Useful for tests — bypasses the native side entirely.

## Types

# envelope()

    @type envelope() :: {:mob_event, Mob.Event.Address.t(), atom(), term()}

The shape of every event message delivered to a handler.

## Functions

# dispatch(pid, addr, event, payload)

    @spec dispatch(pid(), Mob.Event.Address.t(), atom(), term()) :: :ok

Send the event to an already-resolved pid.

Used when the renderer pre-resolved the target at registration time and passes the pid directly. Skips re-resolution.

Also broadcasts to any `Mob.Event.Trace` subscribers (zero cost when no tracers are registered).

# emit(addr, event, payload, target, scope)

    @spec emit(
      Mob.Event.Address.t(),
      atom(),
      term(),
      Mob.Event.Target.spec(),
      Mob.Event.Target.render_scope()
    ) :: :ok

Resolve `target` and deliver the event.

Best-effort delivery: if the target can't be resolved (dead pid, unknown registered name, component not in the ancestor chain), logs a debug message and drops the event.

Returns `:ok` always. Errors from resolution are logged, not raised — losing one event from a stale handle should never crash the BEAM.

# is_event?(arg1)

    @spec is_event?(term()) :: boolean()

True if `msg` matches the canonical event envelope shape.

    iex> Mob.Event.is_event?({:mob_event, %Mob.Event.Address{screen: S, widget: :x, id: :y}, :tap, nil})
    true

    iex> Mob.Event.is_event?({:tap, :something})
    false

# match_address?(addr, filters)

    @spec match_address?(
      Mob.Event.Address.t(),
      keyword()
    ) :: boolean()

True if `addr` matches all the given filters.

Filters is a keyword list of address fields and the values they must equal. Useful for one-off matches in `handle_info/2` clauses where you don't want to write a full struct pattern.

    iex> addr = %Mob.Event.Address{screen: S, widget: :button, id: :save}
    iex> Mob.Event.match_address?(addr, widget: :button)
    true

    iex> addr = %Mob.Event.Address{screen: S, widget: :button, id: :save}
    iex> Mob.Event.match_address?(addr, widget: :button, id: :cancel)
    false

# send_test(pid, screen, widget, id, event, payload \\ nil, opts \\ [])

    @spec send_test(
      pid(),
      atom() | pid(),
      atom(),
      Mob.Event.Address.id(),
      atom(),
      term(),
      keyword()
    ) :: :ok

Synthesize an event delivery to `pid`. Useful for tests — bypasses the native side entirely.

    Mob.Event.send_test(self(), MyScreen, :button, :save, :tap, nil)
    assert_receive {:mob_event, %Address{id: :save}, :tap, nil}