Packages

spark

0.1.1
2.7.2 2.7.1 2.7.0 2.6.1 2.6.0 2.5.0 2.4.1 2.4.0 2.3.14 2.3.13 2.3.12 2.3.11 2.3.10 2.3.9 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.69 2.2.68 2.2.67 2.2.66 2.2.65 2.2.64 2.2.63 2.2.62 2.2.61 2.2.60 2.2.59 2.2.58 2.2.57 2.2.56 2.2.55 2.2.54 2.2.53 2.2.52 2.2.51 2.2.50 2.2.49 2.2.48 2.2.47 2.2.46 2.2.45 2.2.44 2.2.43 2.2.42 2.2.41 2.2.40 2.2.39 2.2.38 2.2.37 2.2.36 2.2.35 2.2.34 2.2.33 2.2.32 2.2.31 2.2.30 2.2.29 2.2.28 2.2.27 2.2.26 2.2.25 2.2.24 2.2.23 2.2.22 2.2.21 2.2.20 2.2.19 2.2.18 2.2.17 2.2.16 2.2.15 2.2.14 2.2.13 2.2.12 2.2.11 2.2.10 2.2.9 2.2.8 2.2.7 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 2.2.1 2.2.0 2.1.24 2.1.23 2.1.22 2.1.21 2.1.20 2.1.19 2.1.18 2.1.17 2.1.16 2.1.15 2.1.14 2.1.13 2.1.12 2.1.11 2.1.10 2.1.9 2.1.8 2.1.7 2.1.6 2.1.5 2.1.4 2.1.3 2.1.2 2.1.1 2.1.0 2.0.1 2.0.0 1.1.55 1.1.54 1.1.53 1.1.52 1.1.51 1.1.50 1.1.49 1.1.48 1.1.47 1.1.46 1.1.45 1.1.44 1.1.43 1.1.42 1.1.41 1.1.40 1.1.39 1.1.38 1.1.37 1.1.36 1.1.35 1.1.34 1.1.32 1.1.31 1.1.30 1.1.29 1.1.28 1.1.27 1.1.26 1.1.25 1.1.24 1.1.22 1.1.21 1.1.20 1.1.19 1.1.18 1.1.17 1.1.16 1.1.15 1.1.14 retired 1.1.13 1.1.12 1.1.11 1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.9 1.0.8 1.0.7 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0.0 0.4.12 0.4.11 0.4.10 0.4.9 0.4.8 0.4.7 0.4.6 0.4.5 0.4.4 0.4.3 0.4.2 0.4.1 0.3.12 0.3.11 0.3.10 0.3.9 0.3.8 0.3.7 0.3.6 0.3.5 0.3.4 0.3.3 0.3.2 0.3.1 0.3.0 0.2.18 0.2.17 0.2.16 0.2.15 0.2.14 0.2.13 0.2.12 0.2.11 0.2.10 0.2.9 0.2.8 0.2.7 0.2.6 0.2.5 0.2.4 0.2.3 0.2.2 0.2.1 0.2.0 0.1.29 0.1.28 0.1.27 0.1.26 0.1.25 0.1.24 0.1.23 0.1.22 0.1.21 0.1.20 0.1.19 0.1.18 0.1.17 0.1.16 0.1.15 0.1.14 0.1.13 0.1.12 0.1.11 0.1.10 0.1.9 0.1.8 0.1.7 0.1.6 0.1.5 0.1.4 0.1.3 0.1.2 0.1.1 0.1.0

Generic tooling for building DSLs

Current section

Files

Jump to
spark lib spark options_helpers.ex
Raw

lib/spark/options_helpers.ex

defmodule Spark.OptionsHelpers do
@moduledoc """
Helpers for working with nimble options
"""
@type schema :: NimbleOptions.schema()
def merge_schemas(left, right, section \\ nil) do
new_right =
Enum.map(right, fn {key, value} ->
{key, Keyword.put(value, :subsection, section)}
end)
Keyword.merge(left, new_right)
end
def validate(opts, schema) do
NimbleOptions.validate(opts, sanitize_schema(schema))
end
def validate!(opts, schema) do
NimbleOptions.validate!(opts, sanitize_schema(schema))
end
def docs(schema) do
schema
|> Enum.reject(fn {_key, opts} ->
opts[:hide]
end)
|> sanitize_schema()
|> Enum.map(fn {key, opts} ->
if opts[:doc] do
{key, Keyword.update!(opts, :doc, &String.replace(&1, "\n\n", " \n"))}
else
{key, opts}
end
end)
|> NimbleOptions.docs()
end
@non_nimble_options [:hide, :as, :snippet, :links]
defp sanitize_schema(schema) do
Enum.map(schema, fn {key, opts} ->
new_opts = Keyword.update!(opts, :type, &sanitize_type(&1, key))
{key, Keyword.drop(new_opts, @non_nimble_options)}
end)
end
defp sanitize_type(type, key) when is_list(type) do
Enum.map(type, &sanitize_type(&1, key))
end
defp sanitize_type(type, key) do
case type do
{:one_of, values} ->
{:in, sanitize_type(values, key)}
{:in, values} ->
{:in, sanitize_type(values, key)}
{:or, subtypes} ->
{:or, sanitize_type(subtypes, key)}
{:tagged_tuple, tag, type} ->
{:custom, __MODULE__, :tagged_tuple, [key, type, tag]}
{:list, values} ->
{:list, sanitize_type(values, key)}
{:spark_behaviour, behaviour, _builtins} ->
{:custom, __MODULE__, :spark_behaviour, [behaviour]}
{:spark_behaviour, behaviour} ->
{:custom, __MODULE__, :spark_behaviour, [behaviour]}
{:behaviour, _behaviour} ->
:atom
{:mfa_or_fun, arity} ->
{:custom, __MODULE__, :mfa_or_fun, [arity]}
{:spark, _type} ->
:atom
:literal ->
:any
type ->
type
end
end
def tagged_tuple({tag, value}, key, type, tag) do
case Spark.OptionsHelpers.validate(
[{key, value}],
[
{key,
[
type: type
]}
]
) do
{:ok, opts} ->
{:ok, {tag, opts[key]}}
{:error, %NimbleOptions.ValidationError{message: message}} ->
{:error, message}
end
end
def tagged_tuple(other, _key, _type, tag) do
{:error,
"Expected a tagged tuple in the form of {#{inspect(tag)}, value}, got: #{inspect(other)}"}
end
def spark_behaviour({module, opts}, _behaviour) when is_atom(module) do
if Keyword.keyword?(opts) do
# We can't check if it implements the behaviour here, unfortunately
# As it may not be immediately available
{:ok, {module, opts}}
else
{:error, "Expected opts to be a keyword, got: #{inspect(opts)}"}
end
end
def spark_behaviour(module, behaviour) when is_atom(module) do
spark_behaviour({module, []}, behaviour)
end
def spark_behaviour(other, _) do
{:error, "Expected a module and opts, got: #{inspect(other)}"}
end
def map(value) when is_map(value), do: {:ok, value}
def map(_), do: {:error, "must be a map"}
@deprecated "Use {:list, :atom} instead"
def list_of_atoms(value) do
if is_list(value) and Enum.all?(value, &is_atom/1) do
{:ok, value}
else
{:error, "Expected a list of atoms"}
end
end
def module_and_opts({module, opts}) when is_atom(module) do
if Keyword.keyword?(opts) do
{:ok, {module, opts}}
else
{:error, "Expected the second element to be a keyword list, got: #{inspect(opts)}"}
end
end
def module_and_opts({other, _}) do
{:error, "Expected the first element to be a module, got: #{inspect(other)}"}
end
def module_and_opts(module) do
module_and_opts({module, []})
end
def mfa_or_fun(value, arity) when is_function(value, arity), do: {:ok, value}
def mfa_or_fun({module, function, args}, _arity)
when is_atom(module) and is_atom(function) and is_list(args),
do: {:ok, {module, function, args}}
def mfa_or_fun(value, _), do: {:ok, value}
def make_required!(options, field) do
Keyword.update!(options, field, &Keyword.put(&1, :required, true))
end
def make_optional!(options, field) do
Keyword.update!(options, field, &Keyword.delete(&1, :required))
end
def set_type!(options, field, type) do
Keyword.update!(options, field, &Keyword.put(&1, :type, type))
end
def set_default!(options, field, value) do
Keyword.update!(options, field, fn config ->
config
|> Keyword.put(:default, value)
|> Keyword.delete(:required)
end)
end
def append_doc!(options, field, to_append) do
Keyword.update!(options, field, fn opt_config ->
Keyword.update(opt_config, :doc, to_append, fn existing ->
existing <> " - " <> to_append
end)
end)
end
end