defmodule Fussy do
defmacro __using__(_opts) do
quote do
import Fussy, only: [fields: 1]
@acc_fields Map.new()
@before_compile Fussy
end
end
defmacro fields(do: block) do
quote do
import Fussy
unquote(block)
defstruct Map.keys(@acc_fields)
@validator Fussy.Utils.map_validator_from_fields(@acc_fields)
@fields Map.keys(@acc_fields) |> MapSet.new()
# cleanup
@acc_fields nil
end
end
defmacro field(name, validator, opts \\ []) do
quote do
import Fussy.Constructors
@acc_fields Map.put(@acc_fields, unquote(name), %{
validator: unquote(validator),
opts: unquote(opts)
})
end
end
defmacro __before_compile__(_env) do
quote do
alias Fussy.Utils
@behaviour Fussy.Validator
def fields, do: @fields
def validator, do: @validator
def new(values) do
validate(@validator, [], values)
end
def new!(values) do
{:ok, struct} = new(values)
struct
end
def validate(%Fussy.Validators.FixedMap{} = v, values), do: validate(v, [], values)
@impl true
def validate(%Fussy.Validators.FixedMap{} = v, path, values) do
case Utils.validate_using(v, path, values) do
{:ok, map} -> {:ok, struct!(%__MODULE__{}, map)}
{:error, reason} -> {:error, reason}
end
end
end
end
end