Musubi.Lifecycle (musubi v0.3.0)

Copy Markdown View Source

Lifecycle hook helpers for Musubi runtime stages.

Stages

StageArityHook arguments
:before_command3(command_name, payload, socket)
:after_command4(command_name, payload, reply, socket)
:handle_async3(name, async_result, socket)
:handle_info2(message, socket)
:after_render2(resolved_elixir_term, socket)
:after_serialize2(wire_term, socket)

:after_render runs after Musubi.Resolver substitutes child placeholders; it sees the Elixir-form output (atom keys, structs, atom values). :after_serialize runs after Musubi.Wire.to_wire/1 converts the resolved output to wire form (string keys, plain maps, atoms-as-strings).

Summary

Functions

Attaches a lifecycle hook for the given stage.

Detaches a lifecycle hook when one is present.

Runs every hook registered for a stage until one halts or all continue.

Returns the required hook function arity for a lifecycle stage.

Returns the supported lifecycle stages in execution order.

Types

hook_entry()

@type hook_entry() :: %{id: hook_id(), fun: hook_fun()}

hook_fun()

@type hook_fun() :: function()

hook_id()

@type hook_id() :: term()

hook_result()

@type hook_result() ::
  {:cont, Musubi.Socket.t()}
  | {:halt, Musubi.Socket.t()}
  | {:halt, term(), Musubi.Socket.t()}

hook_table()

@type hook_table() :: %{optional(stage()) => [hook_entry()]}

stage()

@type stage() ::
  :before_command
  | :after_command
  | :handle_async
  | :handle_info
  | :after_render
  | :after_serialize

Functions

attach_hook(socket, id, stage, fun)

@spec attach_hook(Musubi.Socket.t(), hook_id(), stage(), hook_fun()) ::
  Musubi.Socket.t()

Attaches a lifecycle hook for the given stage.

Examples

iex> socket = %Musubi.Socket{}
iex> socket =
...>   Musubi.Lifecycle.attach_hook(socket, :audit, :after_render, fn _output, socket ->
...>     {:cont, socket}
...>   end)
iex> Musubi.Socket.get_private(socket, :hooks)[:after_render] |> length()
1

detach_hook(socket, id, stage)

@spec detach_hook(Musubi.Socket.t(), hook_id(), stage()) :: Musubi.Socket.t()

Detaches a lifecycle hook when one is present.

Examples

iex> socket =
...>   Musubi.Lifecycle.attach_hook(%Musubi.Socket{}, :audit, :after_render, fn _output, socket ->
...>     {:cont, socket}
...>   end)
iex> socket = Musubi.Lifecycle.detach_hook(socket, :audit, :after_render)
iex> Musubi.Socket.get_private(socket, :hooks)
%{}

run_hooks(socket, stage, hook_args, halt_payloads_allowed?)

@spec run_hooks(Musubi.Socket.t(), stage(), list(), boolean()) ::
  {:cont, Musubi.Socket.t()}
  | {:halt, Musubi.Socket.t()}
  | {:halt, term(), Musubi.Socket.t()}

Runs every hook registered for a stage until one halts or all continue.

Examples

iex> socket =
...>   Musubi.Lifecycle.attach_hook(%Musubi.Socket{}, :mark, :after_render, fn _output, socket ->
...>     {:cont, Musubi.Socket.assign(socket, :seen?, true)}
...>   end)
iex> {:cont, socket} = Musubi.Lifecycle.run_hooks(socket, :after_render, [%{title: "Inbox"}], false)
iex> socket.assigns.seen?
true

stage_arity(stage)

@spec stage_arity(stage()) :: 2 | 3 | 4

Returns the required hook function arity for a lifecycle stage.

StageArityHook arguments
:before_command3(command_name, payload, socket)
:after_command4(command_name, payload, reply, socket)
:handle_async3(name, async_result, socket)
:handle_info2(message, socket)
:after_render2(resolved_elixir_term, socket)
:after_serialize2(wire_term, socket)

Examples

iex> Musubi.Lifecycle.stage_arity(:before_command)
3
iex> Musubi.Lifecycle.stage_arity(:after_command)
4
iex> Musubi.Lifecycle.stage_arity(:after_serialize)
2

stages()

@spec stages() :: [stage()]

Returns the supported lifecycle stages in execution order.

Examples

iex> Musubi.Lifecycle.stages()
[:before_command, :after_command, :handle_async, :handle_info, :after_render, :after_serialize]