Current section

Files

Jump to
want lib want enum.ex
Raw

lib/want/enum.ex

defmodule Want.Enum do
@moduledoc """
Provides type conversions to enumerations.
"""
use Want.Type
@type result :: {:ok, result :: any()} | {:error, reason :: binary()}
@doc """
Cast a given value to an enum value. The given options keyword list must
include an array of valid enum values under the :valid key, otherwise the
function will return an error tuple.
## Options
* `:valid` - List of valid enum values. The input must loosely match one of these.
## Examples
iex> Want.Enum.cast("hello", valid: [:hello, :world])
{:ok, :hello}
iex> Want.Enum.cast("hello", valid: ["hello", :world])
{:ok, "hello"}
"""
@spec cast(value :: any(), opts :: Keyword.t()) :: result()
def cast(value, opts) when is_list(opts) do
with {:ok, opts} <- validate_opts(opts) do
cast(value, opts, Keyword.get(opts, :valid))
end
end
def cast(value, _opts, [value | _]),
do: {:ok, value}
def cast(value, opts, [v | t]) when is_binary(value) and is_binary(v),
do: cast(value, opts, t)
def cast(value, opts, [v | t]) when is_atom(value) and is_atom(v),
do: cast(value, opts, t)
def cast(value, opts, [v | t]) when is_number(value) and is_number(v),
do: cast(value, opts, t)
def cast(value, opts, [v | t] = valid) when is_binary(v) do
case Want.String.cast(value) do
{:ok, value} -> cast(value, opts, valid)
{:error, _} -> cast(value, opts, t)
end
end
def cast(value, opts, [v | t] = valid) when is_integer(v) do
case Want.Integer.cast(value) do
{:ok, value} -> cast(value, opts, valid)
{:error, _} -> cast(value, opts, t)
end
end
def cast(value, opts, [v | t] = valid) when is_float(v) do
case Want.Float.cast(value) do
{:ok, value} -> cast(value, opts, valid)
{:error, _} -> cast(value, opts, t)
end
end
def cast(value, opts, [v | t] = valid) when is_atom(v) do
case Want.Atom.cast(value, exists: true) do
{:ok, value} -> cast(value, opts, valid)
{:error, _} -> cast(value, opts, t)
end
end
def cast(value, _opts, []),
do: {:error, "#{inspect value} did not match any valid enum values."}
#
# Validate that casting options contain required keys.
#
defp validate_opts(opts) do
if is_list(Keyword.get(opts, :valid)) do
{:ok, opts}
else
{:error, "Enum casting options must include a list of valid values under the :valid key."}
end
end
end