-
-
Save rinaldifonseca/c98b73289c154622f8ff74a3cc29d33a to your computer and use it in GitHub Desktop.
Define elixir structs with typespec with single line of code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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