Nous.Util (nous v0.17.0)

View Source

Small shared helpers used across Nous internals.

Summary

Functions

Convert a map's top-level binary keys to already-existing atoms; keys with no existing atom stay binaries (downstream casts simply ignore them).

Convert a binary to an already-existing atom, returning fallback when no such atom exists.

Split a keyword list into {gen_opts, init_opts} for GenServer.start_link/3.

Functions

atomize_keys(map)

@spec atomize_keys(map()) :: map()

Convert a map's top-level binary keys to already-existing atoms; keys with no existing atom stay binaries (downstream casts simply ignore them).

Same atom-safety guarantees as safe_existing_atom/2.

Examples

iex> Nous.Util.atomize_keys(%{"name" => "a"})
%{name: "a"}

safe_existing_atom(value, fallback \\ nil)

@spec safe_existing_atom(term(), term()) :: atom() | term()

Convert a binary to an already-existing atom, returning fallback when no such atom exists.

Never calls String.to_atom/1: these values are routinely attacker-controllable (persisted state, YAML files, provider responses), and minting atoms from them would exhaust the global atom table (atoms are not GC'd; node-wide DoS).

Atoms (including nil) pass through unchanged; any other input returns fallback.

Examples

iex> Nous.Util.safe_existing_atom("ok")
:ok

iex> Nous.Util.safe_existing_atom("no_such_atom_xyz", "no_such_atom_xyz")
"no_such_atom_xyz"

split_gen_opts(opts)

@spec split_gen_opts(keyword()) :: {keyword(), keyword()}

Split a keyword list into {gen_opts, init_opts} for GenServer.start_link/3.

:name (when present and non-nil) goes to the GenServer options; everything else is passed through as init options.

Examples

iex> Nous.Util.split_gen_opts(name: MyServer, foo: 1)
{[name: MyServer], [foo: 1]}