christopheradams / christopheradams/elixir_style_guide
Macro calls placement in a module
- Dominant language
- Elixir
- Stars
- 4.4k
- Forks
- 300
- PR merge metrics
- No merged PRs in 30d
Description
Is there some rule about macro calls placement in a module?
For example imagine such module:
```elixir
defmodule MyApp.Schema do
use Ecto.Schema
import EctoEnum
defenum Status, :status, ~w(active disabled)a
defenum State, :state, ~w(new accepted cancelled finished)a
@required ~w(name number)a
@optional ~w(description)a
@type t() :: %__MODULE__{}
@type id() :: pos_integer()
schema "schema" do
field :name, :string
field :description, :string
field :number, :integer
field :status, Status
field :state, State
end
def changeset(schema, params) do
# ...
end
```
What is correct placement for `defenum` and `schema`?
From my intuition macro calls placement depends on what code they inject.
The `schema` block creates struct so it should have same placement as `defstruct` block while `defenum` creates nested module so should have same placement as `defmodule`.
From such perspective and taking into account current version of this styleguide, module layout should be reorganized in such way:
```elixir
defmodule MyApp.Schema do
use Ecto.Schema
import EctoEnum
@required ~w(name number)a
@optional ~w(description)a
schema "schema" do
field :name, :string
field :description, :string
field :number, :integer
field :status, Status
field :state, State
end
@type t() :: %__MODULE__{}
@type id() :: pos_integer()
defenum Status, :status, ~w(active disabled)a
defenum State, :state, ~w(new accepted cancelled finished)a
def changeset(schema, params) do
# ...
end
```
However if you try to compile something like this it fails with error:
```
== Compilation error in file lib/my_app/schema.ex ==
** (ArgumentError) invalid or unknown type Title for field :title
lib/ecto/schema.ex:2037: Ecto.Schema.check_field_type!/3
lib/ecto/schema.ex:1745: Ecto.Schema.__field__/4
lib/my_app/schema.ex:13: (module)
(stdlib 3.12.1) erl_eval.erl:680: :erl_eval.do_apply/6
```
which means that my intuition about macro calls placement is wrong or at least priority of nested module block should be higher than `defstruct` block.
Maybe this should be discussed in separate issue but [current version](https://github.com/christopheradams/elixir_style_guide/blob/f6fd749c03b35680e69a6461ef58948ca478666b/README.md#module-attribute-ordering) of the guide says that `defstruct` priority is much higher than `defmodule` what looks inconsistent from my point of view because code like this
```elixir
defmodule Example
defstruct origin: __MODULE__, callback_module: Callback
defmodule Callback do
# ...
end
end
```
can't compile even if you use full module name like ` callback_module: __MODULE__.Callback `.
To summarize, this issue has such questions
- Should `defmodule` block have lower priority than `defstruct`?
- What is correct macro calls placement in a module and should this guide contain some rules about it?
Contributor guide
Assessment
This issue has not been assessed yet.