Current section

Files

Jump to
vela lib macros.ex
Raw

lib/macros.ex

defmodule Vela.Macros do
@moduledoc false
alias Vela.Stubs
def make_arity_2(f) when is_function(f, 1),
do: fn _serie, value -> f.(value) end
def make_arity_2(f) when is_function(f, 2),
do: f
defmacro use_config(opts, globals) do
quote do
globals = unquote(globals)
Enum.map(unquote(opts), fn {serie, vela} ->
vela =
vela
|> Keyword.put_new(:sorter, Keyword.get(globals, :sorter, &Stubs.sort/2))
|> Keyword.put_new(:compare_by, Keyword.get(globals, :compare_by, &Stubs.itself/1))
|> Keyword.put_new(:comparator, Keyword.get(globals, :comparator, &Stubs.compare/2))
|> Keyword.put_new(:corrector, Keyword.get(globals, :corrector, &Stubs.correct/3))
|> Keyword.put_new(:threshold, Keyword.get(globals, :threshold, nil))
|> Keyword.update(
:validator,
Keyword.get(globals, :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
defp extra_types(types) when is_list(types) do
Enum.map(types, fn
{k, nil} ->
{k, [{{:., [], [{:__aliases__, [alias: false], [:Vela]}, :value]}, [], []}]}
{k, type} when is_atom(type) ->
{k, [{type, [], []}]}
{k, {{_, _, _} = module, type}} ->
{k, [{{:., [], [module, type]}, [], []}]}
{k, {module, type}} when is_atom(module) and is_atom(type) ->
modules = module |> Module.split() |> Enum.map(&:"#{&1}")
{k, [{{:., [], [{:__aliases__, [alias: false], modules}, type]}, [], []}]}
{k, v} ->
{k, [v]}
end)
end
def use_types(extra_types) when is_list(extra_types) do
extra_types = extra_types(extra_types)
{:%{}, [],
[
{:__struct__, {:__MODULE__, [], Elixir}},
{:__errors__,
[
{{:., [], [{:__aliases__, [alias: false], [:Vela]}, :kv]}, [], []}
]},
{:__meta__, {{:., [], [{:__aliases__, [alias: false], [:Access]}, :t]}, [], []}}
| extra_types
]}
end
def slice_types(types) do
types
|> extra_types()
|> Enum.reverse()
|> Enum.reduce(&{:|, [], [&1, &2]})
end
defmacro do_typedef(nil, opts) do
quote bind_quoted: [opts: opts] do
types = for {k, v} <- opts, do: {k, v[:type]}
@typedoc "The type of this particular `Vela` implementation"
@type t :: unquote(use_types(types))
@typedoc "The possibly type of members of the result of call to `Vela.slice/1`"
@type serie_slice :: unquote(slice_types(types))
@typedoc "The result of call to `Vela.slice/1`"
@type slice :: [serie_slice()]
end
end
defmacro do_typedef(typedef, opts) do
[
quote do
@typedoc "The type of this particular `Vela` implementation"
@type t :: unquote(typedef)
end,
quote bind_quoted: [opts: opts] do
types = for {k, v} <- opts, do: {k, v[:type]}
@typedoc "The possibly type of members of the result of call to `Vela.slice/1`"
@type serie_slice :: unquote(slice_types(types))
@typedoc "The result of call to `Vela.slice/1`"
@type slice :: [serie_slice()]
end
]
end
end