Current section

Files

Jump to
vela lib macros.ex
Raw

lib/macros.ex

defmodule Vela.Macros do
@moduledoc false
alias Vela.Stubs
defmacro use_config(opts) do
quote do
Enum.map(unquote(opts), fn {serie, vela} ->
vela =
vela
|> Keyword.put_new(:sorter, &Stubs.sort/2)
|> Keyword.put_new(:compare_by, &Stubs.itself/1)
|> Keyword.put_new(:comparator, &Stubs.compare/2)
|> Keyword.put_new(:corrector, &Stubs.correct/3)
|> Keyword.put_new(:threshold, nil)
|> Keyword.update(:validator, &Stubs.validate/1, fn existing ->
case existing do
fun when is_function(fun, 1) or is_function(fun, 2) -> fun
m when is_atom(m) -> &m.valid?/2
other -> raise Vela.AccessError, field: :validator
end
end)
{serie, vela}
end)
end
end
def use_types(extra_types) when is_list(extra_types) do
{:%{}, [],
[
{:__struct__, {:__MODULE__, [], Elixir}},
{:__errors__,
[
{{:., [], [{:__aliases__, [alias: false], [:Vela]}, :kv]}, [], []}
]},
{:__meta__, {:keyword, [], []}}
| extra_types
]}
end
defmacro main_ast do
quote do
@doc "Returns the list of series declared on #{__MODULE__}"
@spec series :: [Vela.serie()]
def series, do: @fields_ordered
@doc "Returns the config #{__MODULE__} was declared with"
@spec config :: [{atom(), Vela.options()}]
def config, do: @config
@doc "Returns the config for the serie `serie`, #{__MODULE__} was declared with"
@spec config(Vela.serie()) :: Vela.options()
def config(serie), do: @config[serie]
@doc "Returns the config value for the serie `serie`, #{__MODULE__} was declared with, and key"
@spec config(Vela.serie(), key :: atom(), default :: any()) :: Vela.option()
def config(serie, key, default \\ nil), do: Keyword.get(@config[serie], key, default)
use Vela.Access, @config
@behaviour Vela
@impl Vela
def slice(vela),
do: for({serie, [h | _]} <- vela, do: {serie, h})
@impl Vela
def purge(%__MODULE__{} = vela, validator \\ nil),
do: Vela.purge(vela, validator)
@impl Vela
def delta(%__MODULE__{} = vela, comparator \\ nil),
do: Vela.δ(vela, comparator)
@impl Vela
def equal?(%__MODULE__{} = v1, %__MODULE__{} = v2),
do: Vela.equal?(v1, v2)
end
end
defmacro wrapped_use(opts) when is_list(opts) do
fields = Keyword.keys(opts)
{meta, opts} = Keyword.pop(opts, :mη, [])
typedefs =
for {serie, desc} <- opts do
{
serie,
Keyword.get(desc, :type, [
{{:., [], [{:__aliases__, [alias: false], [:Vela]}, :value]}, [], []}
])
}
end
typedef =
Macro.escape(
{:%{}, [],
[
{:__struct__, {:__MODULE__, [], Elixir}},
{:__errors__,
[
{{:., [], [{:__aliases__, [alias: false], [:Vela]}, :kv]}, [], []}
]},
{:__meta__, {:keyword, [], []}}
| typedefs
]}
)
opts = for {serie, desc} <- opts, do: {serie, Keyword.delete(desc, :type)}
quote generated: true, location: :keep do
{unquote(opts), unquote(meta), unquote(fields), unquote(typedef)}
end
end
defmacro wrapped_use(opts) do
quote generated: true,
location: :keep,
bind_quoted: [opts: opts] do
{meta, opts} = Keyword.pop(opts, :mη, [])
fields = Keyword.keys(opts)
{opts, meta, fields,
use_types(
Enum.zip(
fields,
Stream.cycle([[{{:., [], [{:__aliases__, [alias: false], [:Vela]}, :value]}, [], []}]])
)
)}
end
end
end