View Source Implement reflection functions
Define a plugin that generates reflection functions that can be used to access the fields and parameters of a struct.
Implement
defmodule Guides.Plugins.Reflection do
use TypedStructor.Plugin
@impl TypedStructor.Plugin
defmacro after_definition(definition, _opts) do
quote bind_quoted: [definition: definition] do
fields = Enum.map(definition.fields, &Keyword.fetch!(&1, :name))
enforced_fields =
definition.fields
|> Stream.filter(fn field ->
Keyword.get_lazy(field, :enforce, fn ->
Keyword.get(definition.options, :enforce, false)
end)
end)
|> Stream.map(&Keyword.fetch!(&1, :name))
|> Enum.to_list()
def __typed_structor__(:fields), do: unquote(fields)
def __typed_structor__(:parameters), do: Enum.map(unquote(definition.parameters), &Keyword.fetch!(&1, :name))
def __typed_structor__(:enforced_fields), do: unquote(enforced_fields)
for field <- definition.fields do
name = Keyword.fetch!(field, :name)
type = field |> Keyword.fetch!(:type) |> Macro.escape()
def __typed_structor__(:type, unquote(name)), do: unquote(type)
def __typed_structor__(:field, unquote(name)), do: unquote(Macro.escape(field))
end
end
end
end
Usage
defmodule User do
use TypedStructor
typed_structor do
plugin Guides.Plugins.Reflection
parameter :age
field :name, String.t(), enforce: true
field :age, age, default: 20
end
end
defmodule MyApp do
use TypedStructor
typed_structor module: User, enforce: true do
plugin Guides.Plugins.Reflection
field :name, String.t()
field :age, integer()
end
end
iex> User.__typed_structor__(:fields)
[:name, :age]
iex> User.__typed_structor__(:parameters)
[:age]
iex> MyApp.User.__typed_structor__(:enforced_fields)
[:name, :age]
iex> Macro.to_string(User.__typed_structor__(:type, :age))
"age"