diff --git a/README.md b/README.md index f1051af..889333d 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ To `use` `EctoEnum` with string-backed storage: ```elixir defmodule CustomEnum do - use EctoEnum, "ready", "set", "go" + use EctoEnum, ["ready", "set", "go"] end ``` diff --git a/lib/ecto_enum.ex b/lib/ecto_enum.ex index 1f2606d..d7359d6 100644 --- a/lib/ecto_enum.ex +++ b/lib/ecto_enum.ex @@ -127,19 +127,6 @@ defmodule EctoEnum do defmacro defenum(module, enum) do quote do enum = Macro.escape(unquote(enum)) - [h | _t] = enum - - enum = - cond do - Keyword.keyword?(enum) -> - enum - - is_binary(h) -> - Enum.map(enum, fn value -> {String.to_atom(value), value} end) - - true -> - raise "Enum must be a keyword list or a list of strings" - end defmodule unquote(module) do use EctoEnum.Use, enum diff --git a/lib/ecto_enum/use.ex b/lib/ecto_enum/use.ex index 9d968d0..bdedd54 100644 --- a/lib/ecto_enum/use.ex +++ b/lib/ecto_enum/use.ex @@ -5,6 +5,20 @@ defmodule EctoEnum.Use do defmacro __using__(opts) do quote bind_quoted: [opts: opts] do + [h | _t] = opts + + opts = + cond do + Keyword.keyword?(opts) -> + opts + + is_binary(h) -> + Enum.map(opts, fn value -> {String.to_atom(value), value} end) + + true -> + raise "Enum must be a keyword list or a list of strings" + end + typespec = Typespec.make(Keyword.keys(opts)) @behaviour Ecto.Type @@ -35,6 +49,12 @@ defmodule EctoEnum.Use do def cast(_other), do: :error + for {key, value} <- opts, k <- Enum.uniq([key, value, Atom.to_string(key)]) do + def cast!(unquote(k)), do: unquote(key) + end + + def cast!(other), do: raise Ecto.CastError, type: __MODULE__, value: other + for {key, value} <- opts, k <- Enum.uniq([key, value, Atom.to_string(key)]) do def dump(unquote(k)), do: {:ok, unquote(value)} end @@ -47,6 +67,18 @@ defmodule EctoEnum.Use do raise Ecto.ChangeError, message: msg end + for {key, value} <- opts, k <- Enum.uniq([key, value, Atom.to_string(key)]) do + def dump!(unquote(k)), do: unquote(value) + end + + def dump!(term) do + msg = + "Value `#{inspect(term)}` is not a valid enum for `#{inspect(__MODULE__)}`. " <> + "Valid enums are `#{inspect(__valid_values__())}`" + + raise Ecto.ChangeError, message: msg + end + def embed_as(_), do: :self def equal?(term1, term2), do: term1 == term2