MixとOTP 01: Mixを使ってみる
gumi TECH
Posted on March 5, 2019
本稿はElixir公式サイトの許諾を得て「Introduction to Mix」の解説にもとづき、加筆補正を加えて、ElixirのビルドツールMixについてかいつまんでご説明します。
Elixirでアプリケーションをつくるためには、つぎの3つのツールを使います。
- OTP (Open Telecom Platform): Erlangに備わっている一式のライブラリです。Erlang開発者はOTPを使って、堅牢で耐障害性に優れたアプリケーションが構築できます(「System Architecture」「1 Introduction」参照)。本稿では、OTPとElixirがいくつの面で統合されているか、監視ツリーやイベントマネージャなどを含めて確かめます。
- Mix: Elixirのビルドツールです。アプリケーションをつくってコンパイルし、テストしたり、依存関係を管理するなどのタスクに用います。
- ExUnit: Elixirに備わるテストユニットにもとづくフレームワークです。
ここでは、Mixを使ってはじめてのプロジェクトをつくり、OTP、Mix、ExUnitのさまざまな機能についてご説明します。
はじめてのプロジェクト
Elixirをインストールすると、実行ファイルとしてelixir
とelixirc
およびiex
のほか、mix
という名前のElixirスクリプトも入ります。コマンドラインツールでmix new
に続けてプロジェクト名を打ち込めば、その名前のディレクトリにプロジェクトファイルがつくられます(図001)。
つぎのコマンドでは--module
オプションでモジュール名(KV
)を決めています。デフォルトではプロジェクト名の頭だけが大文字になる(Kv
)ためです。
$ mix new kv --module KV
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/kv.ex
* creating test
* creating test/test_helper.exs
* creating test/kv_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd kv
mix test
Run "mix help" for more commands.
図001■Mixでつくられたプロジェクトファイル
プロジェクトのコンパイル
新たにつくられたプロジェクトフォルダ(kv
)の中にはmix.exs
というファイルが納められます。プロジェクトを設定するファイルです。つぎのふたつのパブリックな関数が定められています。
-
project
: プロジェクトの設定を返します。- プロジェクト名
- バージョンなど
-
application
: アプリケーションファイルをつくるために用いられます。-
mix help compile.app
で説明が示されます。
-
プライベートな関数deps
はproject
関数から呼び出して、プロジェクトの依存関係を定めます。別の関数として分けられているのは、プロジェクトの設定をわかりやすくするためです(mix help deps
で説明が示されます)。
defmodule KV.MixProject do
use Mix.Project
def project do
[
app: :kv,
version: "0.1.0",
elixir: "~> 1.6",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# 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"},
]
end
end
lib
フォルダに納められているのがプロジェクトのファイルです。モジュールには確認用の関数hello
だけが定められています。
defmodule KV do
@moduledoc """
Documentation for KV.
"""
@doc """
Hello world.
## Examples
iex> KV.hello
:world
"""
def hello do
:world
end
end
コマンドラインツールでプロジェクトのディレクトリに切り替えて、mix compile
コマンドでコンパイルできます。
$ cd kv
$ mix compile
Compiling 1 file (.ex)
Generated kv app
コンパイルが済むと、新たにつくられた_build
ディレクトリにmix.exs
の定めにしたがってファイルが納められます(図002)。プロジェクト名に拡張子.app
のファイル(kv.app
)がアプリケーションマニフェストです。また、プロトコルは統合(consolidated
フォルダ)されます(「Elixir入門 16: プロトコル」の「プロトコルの統合」参照)。
図002Mixでコンパイルしてつくられたファイル
プロジェクトがコンパイルされたら、プロジェクトのディレクトリからつぎのコマンドでiex
セッションをはじめるとモジュールが使えるようになります。
$ iex -S mix
iex> KV.hello
:world
テストを走らせる
Mixはプロジェクトのテストのためのファイルを、test
フォルダにふたつつくります(図003)。
図003■testフォルダにつくられたファイル
ひとつは、プロジェクト名に_test.exs
が添えられたファイルです(kv_test.exs
)。lib
ディレクトリのプロジェクトファイル(kv.ex
)に対応します。はじめは、簡単な動作確認のコードしか書かれていません。
defmodule KVTest do
use ExUnit.Case
doctest KV
test "greets the world" do
assert KV.hello() == :world
end
end
注意することがふたつあります。
- テストファイルはElixirスクリプト(
exs
)です。そのため、テストのたびにファイルをコンパイルし直さなくて済みます。 - テストモジュール(
KVTest
)の中では、ExUnit.Case
を用いています。これはテスト用のAPIを加えるモジュールです。そして、test/3
マクロを使って、簡単なテストが定められています。
test
フォルダの中のもうひとつのファイルは、テストのフレームワーク設定を担うtest_helper.exs
です。Mixがテストを実行するたびに必要とされます。
ExUnit.start()
テストを行うには、コマンドラインツールから、つぎのようにmix test
を打ち込んでください。
$ mix test
..
Finished in 0.03 seconds
1 doctest, 1 test, 0 failures
Randomized with seed 71551
mix test
を走らせると、ソースファイルがコンパイルされ、_build
ディレクトリはつくり直されます。アプリケーションマニフェストが改められるのです。これはMixが複数の環境をサポートしていることにもとづきます。
さらに、mix test
を入力したあとには、ExUnitがテスト成功の数だけドットを出力します。また、テストは自動的にランダム化されます。
テスト用ファイル(kv_test.exs)のコードはつぎのように書き替えて、テストをわざと失敗させてみましょう。
assert KV.hello() == :oops # :world
$ mix test
1) test greets the world (KVTest)
test/kv_test.exs:5
Assertion with == failed
code: assert KV.hello() == :oops
left: :world
right: :oops
stacktrace:
test/kv_test.exs:6: (test)
.
Finished in 0.03 seconds
1 doctest, 1 test, 1 failure
Randomized with seed 828995
ExUnitは、失敗するごとに詳しいレポートを出力します。含まれるのはつぎのような情報です。
- テスト名とテストケース
- 失敗したコード(
code
) - 失敗した式の左辺値(
left
)と右辺値(right
)
テスト名のつぎの行には、テストの定められた位置が示されます。この行はそのままコピーしてmix test
コマンドに添えれば、Mixがその場所から読み込んで、テストを始めます。プロジェクトを開発するときに、ひとつのテストだけ特定してすぐに繰り返せるので便利です。
$ mix test test/kv_test.exs:5
スタックトレース(stacktrace
)は、失敗そのものに関わり、テストの情報と、多くの場合ソースファイルのどこで障害が起こったかを示します。
自動コードフォーマット
.formatter.exs
は、mix new
コマンドがつくるファイルです。Elixirにはコードフォーマッタが備わっています。コードベースが自動的に統一されたスタイルに整えられるのです。フォーマッタはmix format
タスクで実行されます。つくられた.formatter.exs
は、mix format
がどのファイルをフォーマットするのか決めます。
フォーマッタを試してみるには、lib
やtest
ディレクトリのファイルのコードに、余分なスペースや改行を加えて保存すればよいでしょう。
defmodule KVTest
do
use ExUnit.Case
doctest KV
test "greets the world" do
assert KV.hello()
== :world
end
end
コマンドラインツールからmix format
コマンドを打ち込めば、コードのフォーマットは整います。
$ mix format
defmodule KVTest do
use ExUnit.Case
doctest KV
test "greets the world" do
assert KV.hello() == :world
end
end
多くのエディタはフォーマッタとの統合機能が組み込まれていて、保存するときやキー操作によりファイルがフォーマットできます。Elixirを学ぶときは、この統合機能を使うと、Elixirの構文が理解しやすくなるでしょう。
企業やチームでの開発には、継続的なインテグレーションサーバーにmix format --check-formatted
を実行することがお勧めです。現在から将来にわたるコードが標準に則ります。
コードフォーマッタについて詳しくは「mix format」をご参照ください。また、「Elixir v1.6 released」も、このバージョンから備わったコードフォーマッタについて説明しています。
環境
Mixには「環境」という考え方があります。この環境によって、開発者はコンパイルなどのオプションを必要に応じて設定できるのです。デフォルトでは、Mixはつぎの3つの環境を認識します。
-
:dev:
Mixがコンパイルなどのタスクをデフォルトで行います。 -
:test:
mix test
が使います。 -
:prod:
プロジェクトを製品として実行します。
環境は現行のプロジェクトのみに適用されます。プロジェクトに加えた依存関係は、デフォルトでは:prod
環境で実行されます。
環境ごとのカスタマイズは、mix.exs
の中でMix.env/0
関数を呼び出して行います。関数の戻り値は現在の環境を示すアトムです。project
関数の中で、start_permanent
オプションに用いられています。
defmodule KV.MixProject do
def project do
[
start_permanent: Mix.env() == :prod,
]
end
end
:start_permanent
の値がtrue
つまり:prod
環境のとき、アプリケーションは永続モードで起動します。すると、アプリケーションの監視ツリーが終了したとき、Erlang VMはクラッシュするのです。:dev
や:test
環境のときは、VMインスタンスを動かし続けた方が、トラブル対応できて便利でしょう。
Mixのデフォルトは:dev
環境です。ただし、test
タスクについては、デフォルトが:test
環境になります。環境は変数MIX_ENV
によって変えられます(「Environments」参照)。
$ MIX_ENV=prod mix compile
Mixはビルドツールです。そのため、製品では使えるとかぎりません。とくに、チームが明確なビルドの手順で進めている場合は使用できない可能性が高いです。したがって、Mix.env/0
を参照するのは、設定ファイル内のmix.exs
の中にかぎるべきでしょう。アプリケーションコード(lib
フォルダ)では決して使わないでください。
さらに詳しく
さらに詳しくは「Mix」をお読みください。mixのソースコードもご覧いただけます。
使えるタスクの一覧はコマンドmix help
で表示されます。
$ mix help
mix # Runs the default task (current: "mix run")
mix app.start # Starts all registered apps
mix app.tree # Prints the application tree
mix archive # Lists installed archives
mix archive.build # Archives this project into a .ez file
mix archive.install # Installs an archive locally
mix archive.uninstall # Uninstalls archives
mix clean # Deletes generated application files
mix cmd # Executes the given command
mix compile # Compiles source files
mix deps # Lists dependencies and their status
mix deps.clean # Deletes the given dependencies' files
mix deps.compile # Compiles dependencies
mix deps.get # Gets all out of date dependencies
mix deps.tree # Prints the dependency tree
mix deps.unlock # Unlocks the given dependencies
mix deps.update # Updates the given dependencies
mix do # Executes the tasks separated by comma
mix escript # Lists installed escripts
mix escript.build # Builds an escript for the project
mix escript.install # Installs an escript locally
mix escript.uninstall # Uninstalls escripts
mix format # Formats the given files/patterns
mix help # Prints help information for tasks
mix hex # Prints Hex help information
mix hex.audit # Shows retired Hex deps for the current project
mix hex.build # Builds a new package version locally
mix hex.config # Reads, updates or deletes local Hex config
mix hex.docs # Fetches or opens documentation of a package
mix hex.info # Prints Hex information
mix hex.organization # Manages Hex.pm organizations
mix hex.outdated # Shows outdated Hex deps for the current project
mix hex.owner # Manages Hex package ownership
mix hex.publish # Publishes a new package version
mix hex.repo # Manages Hex repositories
mix hex.retire # Retires a package version
mix hex.search # Searches for package names
mix hex.user # Manages your Hex user account
mix loadconfig # Loads and persists the given configuration
mix local # Lists local tasks
mix local.hex # Installs Hex locally
mix local.phoenix # Updates Phoenix locally
mix local.phx # Updates the Phoenix project generator locally
mix local.public_keys # Manages public keys
mix local.rebar # Installs Rebar locally
mix new # Creates a new Elixir project
mix phoenix.new # Creates a new Phoenix v1.3.2 application
mix phx.new # Creates a new Phoenix v1.3.2 application
mix phx.new.ecto # Creates a new Ecto project within an umbrella project
mix phx.new.web # Creates a new Phoenix web project within an umbrella project
mix profile.cprof # Profiles the given file or expression with cprof
mix profile.eprof # Profiles the given file or expression with eprof
mix profile.fprof # Profiles the given file or expression with fprof
mix run # Starts and runs the current application
mix test # Runs a project's tests
mix xref # Performs cross reference checks
iex -S mix # Starts IEx and runs the default task
さらに、コマンドのあとに知りたいタスク名を添えて、mix help タスク名
と呼び出せば、タスクごとの詳しい情報も見ることができます(図004)。
図004■タスクの詳細情報を表示する
MixとOTPもくじ
Posted on March 5, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.