# `Localize.Unit.CustomRegistry`
[🔗](https://github.com/elixir-localize/localize/blob/v0.39.0/lib/localize/unit/custom_registry.ex#L1)

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`.

# `all`

```elixir
@spec all() :: %{required(String.t()) =&gt; map()}
```

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

# `clear`

```elixir
@spec clear() :: :ok
```

Removes all custom unit registrations. Primarily for testing.

# `get`

```elixir
@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`

```elixir
@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 {: .warning}
>
> 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.
>
> In a `:prod` Mix environment this function additionally requires
> the `:localize, :allow_runtime_unit_files` config flag to be
> explicitly set to `true`. The flag exists so that an unintended
> feature switch in a production deployment cannot accidentally
> surface arbitrary code execution. Set it in `config/runtime.exs`
> (not `config/config.exs`) so the decision is visible at the same
> layer as other deployment-time policy.

### Arguments

* `path` — path to the `.exs` file.

### Returns

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

* `{:error, reason}` on failure, including a refusal in `:prod`
  when the flag is not set.

# `register`

```elixir
@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`

```elixir
@spec register_batch(%{required(String.t()) =&gt; 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?`

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

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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
