defmodule Hugs do
alias Hugs.StructDefinition
alias Hugs.PropsDefinition
alias Hugs.FieldDefinition
# ---------------------------------------------------------------------------
# Contracts definition helpers
# ---------------------------------------------------------------------------
@doc """
Writes the given definition in the calling module.
"""
defmacro define(dfn) do
dfn_code = Macro.to_string(dfn)
quote bind_quoted: [dfn: dfn, dfn_code: dfn_code], location: :keep do
@__hugs_dfn dfn
require Hugs.Compiler
case @__hugs_dfn do
%Hugs.StructDefinition{} = sdef ->
Hugs.Compiler.define_struct(sdef)
%Hugs.PropsDefinition{} = sdef ->
Hugs.Compiler.define_props(sdef)
other ->
raise """
Hugs.define/1 received unexpected definition.
Got:
#{inspect(other, pretty: true)}
Code:
#{dfn_code}
"""
end
def __hugs__(:definition), do: @__hugs_dfn
end
end
def build_struct(module), do: StructDefinition.new(module)
def build_props(), do: PropsDefinition.new()
defmacro build_struct() do
quote do
Hugs.StructDefinition.new(__MODULE__)
end
end
def field(%cmod{} = container, key, opts \\ []) do
cmod.add_field(container, FieldDefinition.new(key, opts))
end
def constraint(%cmod{} = container, module, fun, args)
when is_atom(module) and is_atom(fun) and is_list(args),
do: cmod.add_constraint(container, module, fun, args)
# ---------------------------------------------------------------------------
# Normalization / Denormalization helpers
# ---------------------------------------------------------------------------
def denormalize(data, target) do
Hugs.Norde.denormalize(data, target)
end
def denormalize!(data, target) do
case denormalize(data, target) do
{:ok, value} -> value
{:error, reason} -> raise reason
end
end
# flipped version of denormalize to pipe the definition instead of the data
def denormalize_data(target, data) do
denormalize(data, target)
end
end