Rho.Dyn.Screens behaviour (rho v0.1.0)

Copy Markdown View Source

How Dyn screens plug into the host's UI: a host seam (config :rho, :dyn, screens: Module, Rho.Dyn.Config). rho builds, checks, selftests and watches Dyn screens the same way whatever the UI; this says what a screen is and how the UI tells the Keeper a launch got going:

  • compiling: which module bodies are screens (screen_source?/1) and the function each screen process enters through (entry/0): the compiler wraps it to register the process with the Keeper first (Rho.Dyn.Keeper.watch/3), so the screen's crash counts against its generation;
  • selftest: which loaded modules are screens (screen?/1, filed as :screen in the registry, Rho.Dyn.screens/1) and how one proves it mounts and renders (selftest/1, run in the contained selftest process);
  • launches: after_first_render/1 has the UI call an MFA (with the screen appended) after its first frame, which starts the clock to "stable" (Rho.Dyn.boot/1); subscribe_app_events/0 and left_app?/1: the app lifecycle events the Keeper receives, and which of them mean the user left the app (a launch that drew its first frame and was left is stable, not failed);
  • the agent's view: live/1, is generation n on screen yet (so dyn_propose with approve-all answers once it is); guide/0, the screen rules for Rho.Dyn.agent_guide/0.

Rho.Dyn.Screens.None (the default) has no screens; Rho.Dyn.Screens.Mob is mob's (use Mob.Screen, mount/3 + render/1).

Summary

Callbacks

Has the UI apply mfa (with the screen module appended) after its first frame.

The function a screen process enters through, {name, arity} (mob: {:mount, 3}).

The screen rules for the agent (Rho.Dyn.agent_guide/0), or nil.

Does message (one the Keeper received) mean the user left the app?

Generation n is current: does the UI show it yet (:live), or not yet (:waiting)? Without this callback, being current is enough (:active).

Is loaded module module a screen?

Do a defmodule's body forms define a screen (its entry gets wrapped)?

Proves screen module works (mounts and renders), in the selftest's contained process: {:ok, detail} or {:error, why}. A raise is a failure.

Subscribes the calling process (the Keeper) to the app's lifecycle events.

Callbacks

after_first_render(mfa)

@callback after_first_render(mfa :: {module(), atom(), list()}) :: :ok

Has the UI apply mfa (with the screen module appended) after its first frame.

entry()

@callback entry() :: {atom(), arity()}

The function a screen process enters through, {name, arity} (mob: {:mount, 3}).

guide()

@callback guide() :: String.t() | nil

The screen rules for the agent (Rho.Dyn.agent_guide/0), or nil.

left_app?(message)

@callback left_app?(message :: term()) :: boolean()

Does message (one the Keeper received) mean the user left the app?

live(n)

(optional)
@callback live(n :: pos_integer()) :: :live | :waiting

Generation n is current: does the UI show it yet (:live), or not yet (:waiting)? Without this callback, being current is enough (:active).

screen?(module)

@callback screen?(module()) :: boolean()

Is loaded module module a screen?

screen_source?(forms)

@callback screen_source?(forms :: [Macro.t()]) :: boolean()

Do a defmodule's body forms define a screen (its entry gets wrapped)?

selftest(module)

@callback selftest(module()) :: {:ok, String.t()} | {:error, String.t()}

Proves screen module works (mounts and renders), in the selftest's contained process: {:ok, detail} or {:error, why}. A raise is a failure.

subscribe_app_events()

@callback subscribe_app_events() :: :ok

Subscribes the calling process (the Keeper) to the app's lifecycle events.