# `Macaw.Data.Derived.Functions`
[🔗](https://github.com/dcoai/macaw_data/blob/v0.5.3/lib/macaw/data/derived/functions.ex#L1)

A host's derived-source functions (spec/02 §7), written as Elixir in the host's own
module and tested with ExUnit:

    defmodule MyApp.Sources do
      use Macaw.Data.Derived.Functions

      defsource health(rows) do
        cpu = Enum.map(rows, & &1.cpu)
        %{state: if(List.last(cpu) > 90, do: :error, else: :ok)}
      end

      defsource bins(inputs, context) do
        %{"bounds" => [lo, hi]} = context["inputs"]["hosts"]["schema"]["cpu"]
        ...
      end
    end

`use Macaw.Data.Derived.Functions` imports `defsource/2` and compiles `__derived__/0`,
each function's name, its arity and its source text, `[{name, arity, source}]` in
definition order. A function of two arguments is called with its inputs and its context
(spec/02 §2.3), one of one argument with its inputs alone. The text is captured when the
module compiles, since a release strips the debug information a later reading would need.

A host's function is trusted (the sandbox's checker does not read it), but it runs
through the same bounded runner as a stored one (`Macaw.Data.Derived.Sandbox.run/3`), so
a runaway ends as a fault, not as its owner's crash. A derived source names it with
`function: :health`; the host passes the module to the registry explicitly, and nothing
else registers one: no application environment is read.

Ported from visualize's `Visualize.VirtualSources`.

## Examples

    iex> defmodule Doc.Sources do
    ...>   use Macaw.Data.Derived.Functions
    ...>   defsource doubled(rows), do: Enum.map(rows, &(&1 * 2))
    ...> end
    iex> Doc.Sources.doubled([1, 2])
    [2, 4]
    iex> Doc.Sources.__derived__()
    [{:doubled, 1, "fn rows -> Enum.map(rows, &(&1 * 2)) end"}]
    iex> Macaw.Data.Derived.Functions.registry([Doc.Sources])
    %{"doubled" => {Doc.Sources, 1}}

# `registry`

```elixir
@type registry() :: %{required(String.t()) =&gt; {module(), 1 | 2}}
```

Each host function's name, its string, by the module that defines it and its arity.

# `defsource`
*macro* 

A host's derived-source function: `defsource name(inputs) do … end` is a public `def` of
one argument, and `defsource name(inputs, context) do … end` one of two, which is called
with its context (spec/02 §2.3); either is recorded with its arity and source text under
the module's `__derived__/0`. A function of several clauses is
defined clause by clause, as any function is, and listed once with every clause.

# `registry`

```elixir
@spec registry([module()]) :: registry()
```

The registry of `modules` (spec/02 §7): each function's name, its string, by the module
that defines it and its arity. Default closed: only the modules given are read. Raises
`ArgumentError` for a module without `__derived__/0` and for a name two modules define.

---

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