View Source Module Directives (use, alias, ...)
Directive Organization
Modules directives are sorted into the following order:
@shortdoc
@moduledoc
(adds@moduledoc false
)@behaviour
use
import
(sorted alphabetically)alias
(sorted alphabetically)require
(sorted alphabetically)- everything else (order unchanged)
Before
defmodule Foo do
@behaviour Lawful
alias A.A
require A
use B
def c(x), do: y
import C
@behaviour Chaotic
@doc "d doc"
def d do
alias X.X
alias H.H
alias Z.Z
import Ecto.Query
X.foo()
end
@shortdoc "it's pretty short"
import A
alias C.C
alias D.D
require C
require B
use A
alias C.C
alias A.A
@moduledoc "README.md"
|> File.read!()
|> String.split("<!-- MDOC !-->")
|> Enum.fetch!(1)
end
After
defmodule Foo do
@shortdoc "it's pretty short"
@moduledoc "README.md"
|> File.read!()
|> String.split("<!-- MDOC !-->")
|> Enum.fetch!(1)
@behaviour Chaotic
@behaviour Lawful
use B
use A.A
import A.A
import C
alias A.A
alias C.C
alias D.D
require A
require B
require C
def c(x), do: y
@doc "d doc"
def d do
import Ecto.Query
alias H.H
alias X.X
alias Z.Z
X.foo()
end
end
If any line previously relied on an alias, the alias is fully expanded when it is moved above the alias:
# Given
alias Foo.Bar
import Bar
# Styled
import Foo.Bar
alias Foo.Bar
Directive Expansion
Expands Module.{SubmoduleA, SubmoduleB}
to their explicit forms for ease of searching.
# Before
import Foo.{Bar, Baz, Bop}
alias Foo.{Bar, Baz.A, Bop}
# After
import Foo.Bar
import Foo.Baz
import Foo.Bop
alias Foo.Bar
alias Foo.Baz.A
alias Foo.Bop
Alias Lifting
When a module with three parts is referenced two or more times, styler creates a new alias for that module and uses it.
# Given
require A.B.C
A.B.C.foo()
A.B.C.bar()
# Styled
alias A.B.C
require C
C.foo()
C.bar()
Styler also notices when you have a module aliased and aren't employing that alias and will do the updates for you.
# Given
alias My.Apps.Widget
x = Repo.get(My.Apps.Widget, id)
# Styled
alias My.Apps.Widget
x = Repo.get(Widget, id)
Collisions
Styler won't lift aliases that will collide with existing aliases, and likewise won't lift any module whose name would collide with a standard library name.
You can specify additional modules to exclude from lifting via the :alias_lifting_exclude
configuration option. For the example above, the following configuration would keep Styler from creating the alias A.B.C
node:
# .formatter.exs
[
plugins: [Styler],
styler: [alias_lifting_exclude: [:C]],
]
Alias Application
Styler applies aliases in those cases where a developer wrote out a full module name without realizing that the module is already aliased.
# Given
alias A.B
alias A.B.C
alias A.B.C.D, as: X
A.B.foo()
A.B.C.foo()
A.B.C.D.woo()
C.D.woo()
# Styled
alias A.B
alias A.B.C
alias A.B.C.D, as: X
B.foo()
C.foo()
X.woo()
X.woo()
Adds @moduledoc false
Adds @moduledoc false
to modules without a moduledoc.
Styler does this for two reasons:
Its appearance during code review is a reminder to the author and reviewer that they may want to document the module. This can otherwise be easily forgotten.
To normalize the use of
@moduledoc false
, because it's preferable to docstrings which convey no actual information.For example:
@moduledoc "The module for functions for interacting with Widgets"
in theWidget
module is crueler code to have written than just@moduledoc false
, because including a string gave the reader hope that the author was going to help them comprehend the module. That false hope causes more harm than just saying "Sorry, you're on your own." (aka@moduledoc false
)
In conformance with the precedent set by Credo, this @moduledoc
is not added if the module's name ends with any of the following:
Test
Mixfile
MixProject
Controller
Endpoint
Repo
Router
Socket
View
HTML
JSON