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
enduse 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}}
Summary
Types
Each host function's name, its string, by the module that defines it and its arity.
Functions
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.
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.
Types
Functions
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.
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.