# `Macaw.Data.Operations.Option`
[🔗](https://github.com/dcoai/macaw_data/blob/v0.5.3/lib/macaw/data/operations/option.ex#L1)

An operation's option declaration and the check of a value against it (spec/04 §1.3).

An option is `%Option{type: type, default: value, required: boolean, frame: :width | nil,
doc: text}`. A required option has no default; an optional one's `default` is filled in
when a node omits it. `frame: :width` makes it frame-bound: a node may write `"plot"`,
the plot's width in whole pixels, resolved before the step runs (spec/04 §3.2).

| Type | Holds |
|---|---|
| `:field` | a column name, a string or an atom |
| `{:list, type}` | a list of `type` |
| `{:pair, type}` | a two-element list of `type` |
| `:name` | the name of a column a step adds, a string or an atom |
| `:number`, `{:number, low, high}` | any number; one in `low..high`, both inclusive |
| `:positive` | a number above zero |
| `:integer`, `{:integer, min}` | any integer; one at least `min` |
| `:power_of_two` | a positive integer power of two |
| `:boolean` | `true` or `false` |
| `{:enum, atoms}` | one of `atoms`, written as the atom or its string |
| `{:keys, type}` | a fixed order: `{:keys, list}`, or a map whose one key is `keys` |
| `{:one_of, types}` | a value of the first of `types` that holds it |
| `:duration` | `[n, unit]`, `unit` one of `units/0` by spelling |
| `:aggregate` | the name of an aggregate in the registry, checked to its module |
| `:term` | any value |

No atom is ever made: an enum value or a unit is matched against the declaration's own
atoms by their strings.

# `t`

```elixir
@type t() :: %Macaw.Data.Operations.Option{
  default: term(),
  doc: String.t(),
  frame: :width | nil,
  required: boolean(),
  type: type()
}
```

# `type`

```elixir
@type type() ::
  :field
  | :name
  | :number
  | {:number, number(), number()}
  | :positive
  | :integer
  | {:integer, integer()}
  | :power_of_two
  | :boolean
  | {:enum, [atom()]}
  | {:keys, type()}
  | {:list, type()}
  | {:pair, type()}
  | {:one_of, [type()]}
  | :duration
  | :aggregate
  | :term
```

# `check`

```elixir
@spec check(Macaw.Data.Operations.Registry.t() | term(), t() | type(), term()) ::
  {:ok, term()} | {:error, term()}
```

The value as a step is given it, or `{:error, reason}`: `{:type, type}` for a value the
type does not hold, `{:unknown, :aggregate, name}` for an aggregate the registry lacks.

    iex> alias Macaw.Data.Operations.Option
    iex> Option.check(:term, {:enum, [:ascending, :descending]}, "descending")
    {:ok, :descending}
    iex> Option.check(:term, {:integer, 0}, -1)
    {:error, {:type, {:integer, 0}}}

# `units`

```elixir
@spec units() :: [{atom(), pos_integer()}]
```

A duration's units and the seconds each names, in order.

---

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