Skip to content

Instantly share code, notes, and snippets.

@rinaldifonseca
Forked from teamon/box.ex
Created February 10, 2024 20:13
Show Gist options
  • Save rinaldifonseca/c98b73289c154622f8ff74a3cc29d33a to your computer and use it in GitHub Desktop.
Save rinaldifonseca/c98b73289c154622f8ff74a3cc29d33a to your computer and use it in GitHub Desktop.
Define elixir structs with typespec with single line of code
defmodule Box do
defmacro __using__(_env) do
quote do
import Box
end
end
@doc """
Define module with struct and typespec, in single line
Example:
use Box
defbox User, id: integer,
name: String.t
is the same as
defmodule User do
@type t :: %__MODULE__{
id: integer,
name: String.t
}
@enforce_keys [:id, :name]
defstruct [:id, :name]
end
"""
defmacro defbox(name, attrs \\ []) do
keys = Keyword.keys(attrs)
quote do
defmodule unquote(name) do
@enforce_keys unquote(keys)
defstruct unquote(keys)
@type t :: %__MODULE__{
unquote_splicing(attrs)
}
end
end
end
end
# Instead of long definition of module
# with struct & typespec & enforce_keys ...
defmodule One do
defmodule User do
@type t :: %__MODULE__{
id: integer,
name: String.t
}
@enforce_keys [:id, :name]
defstruct [:id, :name]
end
defmodule Company do
@type t :: %__MODULE__{
id: integer,
name: String.t,
domain: String.t,
rating: float
}
@enforce_keys [:id, :name, :domain, :rating]
defstruct [:id, :name, :domain, :rating]
end
defmodule Account do
@type t :: %__MODULE__{
user: User.t,
company: Company.t
}
@enforce_keys [:user, :company]
defstruct [:user, :company]
end
end
# ... define all that in much more concise way
defmodule Two do
# include the Box library
use Box
# use defbox to define modules and structs
# in a single line of code
defbox User, id: integer,
name: String.t
defbox Company, id: integer,
name: String.t,
domain: String.t,
rating: float
defbox Account, user: User.t,
company: Company.t
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment