MixとOTP 01: Mixを使ってみる

gumitech

gumi TECH

Posted on March 5, 2019

MixとOTP 01: Mixを使ってみる

本稿は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をインストールすると、実行ファイルとしてelixirelixircおよびiexのほか、mixという名前のElixirスクリプトも入ります。コマンドラインツールでmix newに続けてプロジェクト名を打ち込めば、その名前のディレクトリにプロジェクトファイルがつくられます(図001)。

つぎのコマンドでは--moduleオプションでモジュール名(KV)を決めています。デフォルトではプロジェクト名の頭だけが大文字になる(Kv)ためです。

$ mix new kv --module KV
Enter fullscreen mode Exit fullscreen mode
* 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.
Enter fullscreen mode Exit fullscreen mode

図001■Mixでつくられたプロジェクトファイル

mix_otp_01_001.png

プロジェクトのコンパイル

新たにつくられたプロジェクトフォルダ(kv)の中にはmix.exsというファイルが納められます。プロジェクトを設定するファイルです。つぎのふたつのパブリックな関数が定められています。

  • project: プロジェクトの設定を返します。
    • プロジェクト名
    • バージョンなど
  • application: アプリケーションファイルをつくるために用いられます。
    • mix help compile.appで説明が示されます。

プライベートな関数depsproject関数から呼び出して、プロジェクトの依存関係を定めます。別の関数として分けられているのは、プロジェクトの設定をわかりやすくするためです(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
Enter fullscreen mode Exit fullscreen mode

libフォルダに納められているのがプロジェクトのファイルです。モジュールには確認用の関数helloだけが定められています。

defmodule KV do
  @moduledoc """
  Documentation for KV.
  """

  @doc """
  Hello world.

  ## Examples

      iex> KV.hello
      :world

  """
  def hello do
    :world
  end
end
Enter fullscreen mode Exit fullscreen mode

コマンドラインツールでプロジェクトのディレクトリに切り替えて、mix compileコマンドでコンパイルできます。

$ cd kv
$ mix compile
Enter fullscreen mode Exit fullscreen mode
Compiling 1 file (.ex)
Generated kv app
Enter fullscreen mode Exit fullscreen mode

コンパイルが済むと、新たにつくられた_buildディレクトリにmix.exsの定めにしたがってファイルが納められます(図002)。プロジェクト名に拡張子.appのファイル(kv.app)がアプリケーションマニフェストです。また、プロトコルは統合(consolidatedフォルダ)されます(「Elixir入門 16: プロトコル」の「プロトコルの統合」参照)。

図002Mixでコンパイルしてつくられたファイル

mix_otp_01_002.png

プロジェクトがコンパイルされたら、プロジェクトのディレクトリからつぎのコマンドでiexセッションをはじめるとモジュールが使えるようになります。

$ iex -S mix
Enter fullscreen mode Exit fullscreen mode
iex> KV.hello
:world
Enter fullscreen mode Exit fullscreen mode

テストを走らせる

Mixはプロジェクトのテストのためのファイルを、testフォルダにふたつつくります(図003)。

図003■testフォルダにつくられたファイル

mix_otp_01_003.png

ひとつは、プロジェクト名に_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
Enter fullscreen mode Exit fullscreen mode

注意することがふたつあります。

  1. テストファイルはElixirスクリプト(exs)です。そのため、テストのたびにファイルをコンパイルし直さなくて済みます。
  2. テストモジュール(KVTest)の中では、ExUnit.Caseを用いています。これはテスト用のAPIを加えるモジュールです。そして、test/3マクロを使って、簡単なテストが定められています。

testフォルダの中のもうひとつのファイルは、テストのフレームワーク設定を担うtest_helper.exsです。Mixがテストを実行するたびに必要とされます。

ExUnit.start()
Enter fullscreen mode Exit fullscreen mode

テストを行うには、コマンドラインツールから、つぎのようにmix testを打ち込んでください。

$ mix test
..

Finished in 0.03 seconds
1 doctest, 1 test, 0 failures

Randomized with seed 71551
Enter fullscreen mode Exit fullscreen mode

mix testを走らせると、ソースファイルがコンパイルされ、_buildディレクトリはつくり直されます。アプリケーションマニフェストが改められるのです。これはMixが複数の環境をサポートしていることにもとづきます。

さらに、mix testを入力したあとには、ExUnitがテスト成功の数だけドットを出力します。また、テストは自動的にランダム化されます。

テスト用ファイル(kv_test.exs)のコードはつぎのように書き替えて、テストをわざと失敗させてみましょう。

assert KV.hello() == :oops  # :world
Enter fullscreen mode Exit fullscreen mode
$ 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
Enter fullscreen mode Exit fullscreen mode

ExUnitは、失敗するごとに詳しいレポートを出力します。含まれるのはつぎのような情報です。

  • テスト名とテストケース
  • 失敗したコード(code)
  • 失敗した式の左辺値(left)と右辺値(right)

テスト名のつぎの行には、テストの定められた位置が示されます。この行はそのままコピーしてmix testコマンドに添えれば、Mixがその場所から読み込んで、テストを始めます。プロジェクトを開発するときに、ひとつのテストだけ特定してすぐに繰り返せるので便利です。

$ mix test test/kv_test.exs:5
Enter fullscreen mode Exit fullscreen mode

スタックトレース(stacktrace)は、失敗そのものに関わり、テストの情報と、多くの場合ソースファイルのどこで障害が起こったかを示します。

自動コードフォーマット

.formatter.exsは、mix newコマンドがつくるファイルです。Elixirにはコードフォーマッタが備わっています。コードベースが自動的に統一されたスタイルに整えられるのです。フォーマッタはmix formatタスクで実行されます。つくられた.formatter.exsは、mix formatがどのファイルをフォーマットするのか決めます。

フォーマッタを試してみるには、libtestディレクトリのファイルのコードに、余分なスペースや改行を加えて保存すればよいでしょう。

defmodule KVTest
do

  use ExUnit.Case

  doctest KV

  test "greets the world" do

    assert KV.hello()
    == :world

  end
end
Enter fullscreen mode Exit fullscreen mode

コマンドラインツールからmix formatコマンドを打ち込めば、コードのフォーマットは整います。

$ mix format
Enter fullscreen mode Exit fullscreen mode
defmodule KVTest do
  use ExUnit.Case

  doctest KV

  test "greets the world" do
    assert KV.hello() == :world
  end
end
Enter fullscreen mode Exit fullscreen mode

多くのエディタはフォーマッタとの統合機能が組み込まれていて、保存するときやキー操作によりファイルがフォーマットできます。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
Enter fullscreen mode Exit fullscreen mode

:start_permanentの値がtrueつまり:prod環境のとき、アプリケーションは永続モードで起動します。すると、アプリケーションの監視ツリーが終了したとき、Erlang VMはクラッシュするのです。:dev:test環境のときは、VMインスタンスを動かし続けた方が、トラブル対応できて便利でしょう。

Mixのデフォルトは:dev環境です。ただし、testタスクについては、デフォルトが:test環境になります。環境は変数MIX_ENVによって変えられます(「Environments」参照)。

$ MIX_ENV=prod mix compile
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

さらに、コマンドのあとに知りたいタスク名を添えて、mix help タスク名と呼び出せば、タスクごとの詳しい情報も見ることができます(図004)。

図004■タスクの詳細情報を表示する

mix_otp_01_004.png

MixとOTPもくじ

💖 💪 🙅 🚩
gumitech
gumi TECH

Posted on March 5, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related