defmodule Fussy.Validators.Atom do
@behaviour Fussy.Validator
alias Fussy.ValidationError
defstruct [:atom, :case_sensitive]
@opaque t :: %__MODULE__{}
@spec new(atom(), case_sensitive: bool()) :: __MODULE__.t()
def new(atom, args \\ []), do: struct!(%__MODULE__{atom: atom}, args)
def validate(%__MODULE__{} = v, term), do: validate(v, [], term)
@impl true
def validate(%__MODULE__{atom: atom}, _path, atom), do: {:ok, atom}
@impl true
def validate(%__MODULE__{atom: atom, case_sensitive: false} = v, path, term)
when is_binary(term) do
if String.downcase(term) == Atom.to_string(atom) |> String.downcase() do
{:ok, atom}
else
error(v, path, term)
end
end
@impl true
def validate(%__MODULE__{atom: atom, case_sensitive: false} = v, path, term)
when is_atom(term) do
if Atom.to_string(term) |> String.downcase() == Atom.to_string(atom) |> String.downcase() do
{:ok, atom}
else
error(v, path, term)
end
end
@impl true
def validate(%__MODULE__{atom: atom} = v, path, term) when is_binary(term) do
if atom == String.to_existing_atom(term) do
{:ok, atom}
else
error(v, path, term)
end
rescue
_ in ArgumentError -> error(v, path, term)
end
@impl true
def validate(%__MODULE__{} = v, path, term), do: error(v, path, term)
defp error(%__MODULE__{atom: atom}, path, term) do
{:error,
[
%ValidationError{
mod: __MODULE__,
path: path,
msg: "must be #{inspect(atom)} or \"#{atom}\"",
term: term
}
]}
end
end