Packages

A normalization/denormalization that works well with Elixir datastructures.

Current section

Files

Jump to
hugs lib hugs compiler.ex
Raw

lib/hugs/compiler.ex

defmodule Hugs.Compiler do
alias Hugs.StructDefinition
alias Hugs.PropsDefinition
defmacro denormalize_funs(opts) do
quote bind_quoted: binding(), location: :keep do
@__hugs_denormalize_opts opts
denormalize_callstack =
[
quote do
Hugs.Norde.denormalize(__hugs__(:definition))
end
# Add more denormalization calls. Note that those will only apply when
# calling the denormalize function from this module, i.e. they will
# not be applied if this module is embedded.
]
|> Enum.filter(&(&1 != nil))
|> Enum.reduce(quote(do: data), fn call, expr -> Macro.pipe(expr, call, 0) end)
defp __hugs_denorm__(data), do: unquote(denormalize_callstack)
defp __hugs_denorm__!(data) do
case __hugs_denorm__(data) do
{:ok, value} -> value
{:error, err} -> raise err
end
end
@spec denormalize(map) :: {:ok, t()} | {:error, term}
def denormalize(data), do: __hugs_denorm__(data)
@spec denormalize!(map) :: t()
def denormalize!(data), do: __hugs_denorm__!(data)
@doc """
Create a new `#{inspect(__MODULE__)}` struct from a list of properties.
"""
@spec of(kvs()) :: t()
def of(kvs)
def of([{_, _} | _] = kvs), do: __hugs_denorm__!({:mapdata, kvs})
def of([] = kvs), do: __hugs_denorm__!({:mapdata, kvs})
@doc """
Create a new `#{inspect(__MODULE__)}` struct from a map or a struct.
"""
if opts[:struct] do
@spec new(kvs() | as_map() | t()) :: t()
else
@spec new(kvs() | t()) :: t()
end
def new(props)
def new(map) when is_map(map), do: __hugs_denorm__!(map)
def new([{_, _} | _] = kvs), do: __hugs_denorm__!({:mapdata, kvs})
def new([]), do: __hugs_denorm__!({:mapdata, []})
end
end
defmacro define_struct(quoted_dfn) do
quote bind_quoted: [dfn: quoted_dfn] do
required_keys = StructDefinition.required_keys(dfn)
defaults = StructDefinition.default_pairs(dfn)
@enforce_keys required_keys
defstruct defaults
@type t :: unquote(Hugs.TypeDef.to_quoted(dfn))
@type as_map :: unquote(Hugs.TypeDef.to_quoted(dfn.props))
Hugs.Compiler.def_kvs_type(dfn.props)
Hugs.Compiler.denormalize_funs(struct: true)
end
end
defmacro define_props(quoted_dfn) do
quote bind_quoted: [dfn: quoted_dfn] do
required_keys = PropsDefinition.required_keys(dfn)
defaults = PropsDefinition.default_pairs(dfn)
@type t :: unquote(Hugs.TypeDef.to_quoted(dfn))
Hugs.Compiler.def_kvs_type(dfn)
Hugs.Compiler.denormalize_funs(struct: false)
end
end
defmacro def_kvs_type(quoted_dfn) do
quote bind_quoted: [dfn: quoted_dfn] do
@type kv :: unquote(Hugs.TypeDef.to_quoted_kvs(dfn))
@type kvs :: [kv]
end
end
end