Packages

Placeholders for data that isn't loaded. Inspired by Ecto.

Current section

Files

Jump to
not_loaded lib not_loaded.ex
Raw

lib/not_loaded.ex

defmodule NotLoaded do
@moduledoc """
Struct returned by fields when they have not been loaded.
## Example
# Define your NotLoaded module
NotLoaded.defmodule(MyApp.NotLoaded)
# Use this module in your application
defmodule MyApp.Book do
import MyApp.NotLoaded, only: [lazy_loaded: 1]
defstruct [
:title,
lazy_loaded(:author)
]
end
"""
defstruct [:__field__]
@type field_name :: atom
@type t :: %__MODULE__{
__field__: field_name
}
defimpl Inspect do
def inspect(not_loaded, _opts) do
msg = "field #{inspect(not_loaded.__field__)} is not loaded"
"##{inspect(@for)}<#{msg}>"
end
end
@doc """
Creates a new `NotLoaded` struct for a given field name.
"""
@deprecated "Use defmodule/1 to define an application specific NotLoaded module, instead"
@spec new(field_name) :: t
def new(field_name) do
%__MODULE__{__field__: field_name}
end
@doc """
Defaults a struct field to `NotLoaded`.
"""
@deprecated "Use `defmodule/1` to define an application specific NotLoaded module, instead"
defmacro lazy_loaded(field_name) when is_atom(field_name) do
quote do
{unquote(field_name), unquote(__MODULE__).new(unquote(field_name))}
end
end
@doc """
Generate a NotLoaded module
"""
def defmodule(name) when is_atom(name) do
contents =
quote do
@moduledoc """
Struct returned for fields when they are not loaded.
The fields are:
* `__field__` - the field on `__owner__` struct that is not loaded
* `__owner__` - the module of the struct that defined this field
"""
defstruct [:__field__, :__owner__]
@type field_name :: atom
@type t :: %__MODULE__{
__field__: field_name,
__owner__: module
}
defimpl Inspect do
def inspect(not_loaded, _opts) do
msg = "field #{inspect(not_loaded.__field__)} is not loaded"
"##{inspect(@for)}<#{msg}>"
end
end
@doc """
Defaults a struct field to `#{inspect(__MODULE__)}`.
Automatically populates `__field__` and `__owner__`.
## Example
defmodule MyStruct do
import #{inspect(__MODULE__)}, only: [lazy_loaded: 1]
defstruct [
:title,
lazy_loaded(:author)
]
end
"""
defmacro lazy_loaded(field_name) when is_atom(field_name) do
quote do
{unquote(field_name),
%unquote(__MODULE__){__field__: unquote(field_name), __owner__: __MODULE__}}
end
end
end
Module.create(name, contents, Macro.Env.location(__ENV__))
end
end