私が $ mix new foo
でライブラリを新規作成したあとに毎回必ずやっていること。
2018年12月現在は以下の4つだ。
- ドキュメント生成ツール ex_doc 追加
- 静的解析ツール dialyxir 追加(型チェック)
- 静的解析ツール credo 追加(Lint)
- フォーマッタで折り返される1行あたりの文字数を120にする
ドキュメント生成ツール ex_doc
ex_doc は Elixir を用いたプロジェクトのドキュメントを生成してくれるライブラリ。それだけでなく Elixir 自身のドキュメントも ex_doc を用いて出力されている。
mix.exs に追加する
diff --git a/mix.exs b/mix.exs
index f6d766a..d18402d 100644
--- a/mix.exs
+++ b/mix.exs
@@ -21,8 +21,7 @@ defmodule Foo.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
- # {:dep_from_hexpm, "~> 0.3.0"},
- # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
+ {:ex_doc, "~> 0.19", only: :dev, runtime: false}
]
end
end
使う
mix deps.get
と mix deps.compile
の両方を行ってからでないと mix docs
コマンドが出てこないので注意すること。
$ mix deps.get
$ mix deps.compile
$ mix docs
Compiling 1 file (.ex)
Generated foo app
Docs successfully generated.
View them at "doc/index.html".
doc/index.html
を開くと
このようなドキュメントが表示できる。
静的解析ツール dialyxir
dialyxir は ErlangVM 向け静的解析ツール dialyzer を mix コマンドから簡潔に使えるようにしたもの。
mix.exs に追加する
diff --git a/mix.exs b/mix.exs
index d18402d..5f588ae 100644
--- a/mix.exs
+++ b/mix.exs
@@ -21,7 +21,8 @@ defmodule Foo.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
- {:ex_doc, "~> 0.19", only: :dev, runtime: false}
+ {:ex_doc, "~> 0.19", only: :dev, runtime: false},
+ {:dialyxir, "~> 1.0.0-rc.4", only: :dev, runtime: false}
]
end
end
使う
mix deps.get
と mix deps.compile
の両方を行ってからでないと mix dialyzer
コマンドが出てこないので注意すること。
mix dialyzer
は初回実行にすごく時間がかかる。これはそういうものなのであきらめよう。2回目以降は1回目に生成したPLTと呼ばれるキャッシュを利用するのでかなり改善される。
$ mix deps.get
$ mix deps.compile
$ time mix dialyzer
Total errors: 0, Skipped: 0
done (passed successfully)
337.91 real 805.19 user 41.86 sys
$ time mix dialyzer
Total errors: 0, Skipped: 0
done in 0m1.02s
done (passed successfully)
1.62 real 1.70 user 0.32 sys
誤りを検出した場合にどう動作するか
lib/foo/foo.ex
を以下のように書き換えて試す。add
という関数を追加した。
Elixir 界では +
が使えるのは number
型のみなのでエラーが検出できるはず。
defmodule Foo do
@moduledoc """
Documentation for Foo.
"""
@doc """
Hello world.
## Examples
iex> Foo.hello()
:world
"""
def hello do
result = add("x", "y")
:world
end
def add(a, b) do
a + b
end
end
$ mix dialyzer
Total errors: 2, Skipped: 0
done in 0m1.18s
lib/foo.ex:15:no_return
Function hello/0 has no local return.
________________________________________________________________________________
lib/foo.ex:16:call
The call:
Foo.add("x", <<_::8>>)
will never return since it differs in arguments with
positions 1st and 2nd from the success typing arguments:
(number(), number())
________________________________________________________________________________
done (warnings were emitted)
Foo.add の引数の型は number()
と number()
であるはずだと言われている。
うまく動作しているようだ。
(lib/foo/foo.ex
を元に戻す)
静的解析ツール credo
credo も先程の dialyxir と同様に静的解析ツールだ。ただ着目しているところが異なり credo はコードの一貫性を保つことや、より望ましいコードとなるよう手引きするためにある。いわゆる Lint ツールだ。
mix.exs に追加する
diff --git a/mix.exs b/mix.exs
index 5f588ae..ad6948a 100644
--- a/mix.exs
+++ b/mix.exs
@@ -22,7 +22,8 @@ defmodule Foo.MixProject do
defp deps do
[
{:ex_doc, "~> 0.19", only: :dev, runtime: false},
- {:dialyxir, "~> 1.0.0-rc.4", only: :dev, runtime: false}
+ {:dialyxir, "~> 1.0.0-rc.4", only: :dev, runtime: false},
+ {:credo, "~> 1.0.0", only: :dev, runtime: false}
]
end
end
使う
mix deps.get
と mix deps.compile
の両方を行ってからでないと mix credo
コマンドが出てこないので注意すること。
$ mix deps.get
$ mix deps.compile
$ mix credo
Checking 3 source files ...
Please report incorrect results: https://github.com/rrrene/credo/issues
Analysis took 0.1 seconds (0.01s to load, 0.1s running checks)
3 mods/funs, found no issues.
Use `--strict` to show all issues, `--help` for options.
mix credo するとき、チェック設定を .credo.exs
というファイルから自動的に読み込んでくれる。ファイルを置ける有効な場所はルートディレクトリか、config/
だ。昨今のルートディレクトリは様々な物が置かれて混雑するので、私は config/
に置いている。
またそのチェック設定のファイルを mix credo.gen.config
で生成できる。
そこで生成して config/
に置く。
$ mix credo.gen.config
$ mv .credo.exs config/
望ましくないコードを検出したらどう動くか。
lib/foo/foo.ex
を以下のように書き換えて試す。@moduledoc
という、モジュールに対するドキュメントを取り去った。
defmodule Foo do
@doc """
Hello world.
## Examples
iex> Foo.hello()
:world
"""
def hello do
:world
end
end
そうすると
$ mix credo
Checking 3 source files ...
Code Readability
┃
┃ [R] → Modules should have a @moduledoc tag.
┃ lib/foo.ex:1:11 #(Foo)
Please report incorrect results: https://github.com/rrrene/credo/issues
Analysis took 0.1 seconds (0.00s to load, 0.1s running checks)
3 mods/funs, found 1 code readability issue.
という形式で望ましくない部分が検出される。
(lib/foo/foo.ex
を元に戻す)
フォーマッタで折り返される1行あたりの文字数を120にする
Elixir1.6 からはフォーマッタが標準添付されており mix format
でフォーマットできる。デフォルト時に何文字で折り返すかは Code.format_string!/2 に書かれているとおり 98 文字だ。私はこれだと少し短く感じたので 120 文字にしている。120 文字は credo で文字の横幅が長すぎるときに出すデフォルト値でもあるので丁度よい。
1行あたりの文字数、他にどんな候補があるかは Elixirでは行の最大長をいくつにするべきか をみてほしい。
変更するには .formatter.exs
に設定を追加すればよい。
diff --git a/.formatter.exs b/.formatter.exs
index d2cda26..0a70dc0 100644
--- a/.formatter.exs
+++ b/.formatter.exs
@@ -1,4 +1,5 @@
# Used by "mix format"
[
- inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
+ inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
+ line_length: 120
]