Localize.Unit.CustomRegistry (Localize v0.14.0)

Copy Markdown View Source

Runtime registry for user-defined units backed by :persistent_term.

Custom units are stored in a single map keyed by unit name. The registry is checked by Localize.Unit.Data, Localize.Unit.BaseUnit, Localize.Unit.Conversion, and the unit formatter to overlay runtime definitions on top of the compile-time CLDR data.

Definition structure

Each definition is a map with the following keys:

  • :base_unit (required) — the CLDR base unit this custom unit converts to (e.g., "meter", "kilogram", "second").

  • :factor (required) — the conversion factor: 1 custom_unit = factor * base_unit.

  • :offset (optional) — additive offset for the conversion. Defaults to 0.0.

  • :category (required) — the unit category (e.g., "length", "mass").

  • :display (optional) — locale-specific display patterns. A nested map of locale => style => plural_patterns.

Summary

Functions

Returns all registered custom units as a map of name to definition.

Removes all custom unit registrations. Primarily for testing.

Returns the definition for a custom unit, or nil if not registered.

Loads custom unit definitions from an .exs file.

Registers a custom unit definition.

Registers multiple custom units in a single persistent_term update.

Returns whether a unit name is registered in the custom registry.

Functions

all()

@spec all() :: %{required(String.t()) => map()}

Returns all registered custom units as a map of name to definition.

clear()

@spec clear() :: :ok

Removes all custom unit registrations. Primarily for testing.

get(unit_name)

@spec get(String.t()) :: map() | nil

Returns the definition for a custom unit, or nil if not registered.

Arguments

  • unit_name — the unit identifier string.

Returns

  • A definition map or nil.

load_file(path)

@spec load_file(String.t()) :: {:ok, non_neg_integer()} | {:error, String.t()}

Loads custom unit definitions from an .exs file.

The file must evaluate to a list of maps, each with a :unit key and the standard definition fields.

Security

This function uses Code.eval_file/1 to evaluate the given file, which executes arbitrary Elixir code. Only load files from trusted sources. Never call this function with unsanitised user input or paths derived from external data.

Arguments

  • path — path to the .exs file.

Returns

  • {:ok, count} with the number of units loaded.

  • {:error, reason} on failure.

register(name, definition)

@spec register(String.t(), map()) :: :ok | {:error, String.t()}

Registers a custom unit definition.

Arguments

  • name — the unit identifier string.

  • definition — a map with :base_unit, :factor, and :category keys.

Returns

  • :ok on success.

  • {:error, reason} if validation fails.

register_batch(definitions)

@spec register_batch(%{required(String.t()) => map()}) :: {:ok, non_neg_integer()}

Registers multiple custom units in a single persistent_term update.

This is significantly more memory-efficient than calling register/2 in a loop, because it avoids creating intermediate persistent_term snapshots for each unit. Each snapshot is stored in the BEAM's literal area and is not freed until a global garbage collection sweep, so bulk registration via register/2 can exhaust literal memory.

Arguments

  • definitions — a map of %{name => definition} where each definition has :base_unit, :factor, and :category keys.

Returns

  • {:ok, count} with the number of units registered.

  • {:error, reason} if any validation fails. No units are registered on error (the operation is atomic).

registered?(unit_name)

@spec registered?(String.t()) :: boolean()

Returns whether a unit name is registered in the custom registry.