Packages
mob
0.5.17
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.26
0.6.25
0.6.24
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.2
0.6.1
0.6.0
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.11
0.5.10
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.0
BEAM-on-device mobile framework for Elixir
Current section
Files
Jump to
Current section
Files
lib/mob/registry.ex
defmodule Mob.Registry do
@moduledoc """
Maps component names (atoms) to their platform-specific NIF constructors.
Each entry maps a component name to a per-platform tuple:
`{nif_module, function_name, extra_args}`.
## Example
Mob.Registry.register(MyReg, :map_view,
android: {:mob_nif, :create_map_view, []},
ios: {:mob_nif, :create_map_view, []}
)
{:ok, {mod, fun, args}} = Mob.Registry.lookup(MyReg, :map_view, :android)
apply(mod, fun, args)
## Default registry
`Mob.Registry` itself is started by the Mob application and pre-populated
with the built-in component vocabulary. Third-party packages call
`Mob.Registry.register/3` in their `Application.start/2`.
"""
use Agent
# Built-in component mappings — same NIF module for both platforms for now
@builtins [
column: [android: {:mob_nif, :create_column, []}, ios: {:mob_nif, :create_column, []}],
row: [android: {:mob_nif, :create_row, []}, ios: {:mob_nif, :create_row, []}],
text: [android: {:mob_nif, :create_label, []}, ios: {:mob_nif, :create_label, []}],
button: [android: {:mob_nif, :create_button, []}, ios: {:mob_nif, :create_button, []}],
scroll: [android: {:mob_nif, :create_scroll, []}, ios: {:mob_nif, :create_scroll, []}]
]
@doc """
Start a registry Agent.
Pass `name: nil` for an anonymous registry (useful in tests).
Pass `name: Mob.Registry` for the global application registry.
"""
@spec start_link(keyword()) :: Agent.on_start()
def start_link(opts \\ []) do
name = Keyword.get(opts, :name, __MODULE__)
initial = build_initial()
if name do
Agent.start_link(fn -> initial end, name: name)
else
Agent.start_link(fn -> initial end)
end
end
@doc """
Register a component name with platform-specific NIF constructors.
`mappings` is a keyword list of `platform: {mod, fun, args}` entries.
Calling register again for an existing name merges/overwrites platforms.
"""
@spec register(GenServer.server(), atom(), keyword()) :: :ok
def register(registry \\ __MODULE__, name, mappings) when is_atom(name) and is_list(mappings) do
Agent.update(registry, fn state ->
existing = Map.get(state, name, %{})
updated =
Enum.reduce(mappings, existing, fn {platform, spec}, acc ->
Map.put(acc, platform, spec)
end)
Map.put(state, name, updated)
end)
end
@doc """
Look up the NIF spec for a component on a given platform.
Returns `{:ok, {mod, fun, args}}` or `{:error, :not_found}`.
"""
@spec lookup(GenServer.server(), atom(), atom()) ::
{:ok, {module(), atom(), list()}} | {:error, :not_found}
def lookup(registry \\ __MODULE__, name, platform) when is_atom(name) and is_atom(platform) do
state = Agent.get(registry, & &1)
case get_in(state, [name, platform]) do
nil -> {:error, :not_found}
spec -> {:ok, spec}
end
end
@doc """
List all registered component names.
"""
@spec all(GenServer.server()) :: [atom()]
def all(registry \\ __MODULE__) do
Agent.get(registry, &Map.keys/1)
end
# ── Private ───────────────────────────────────────────────────────────────
defp build_initial do
Enum.reduce(@builtins, %{}, fn {name, mappings}, acc ->
Map.put(acc, name, Map.new(mappings))
end)
end
end