ElixirでCLI(Command Line Interface)を作るには、mixを使う必要があるようです。
今回はmixを使ってechoコマンド作り、
「mixとは何で、CLIを作るのに最低限必要なことは何か」を理解しようと思います。
※mixを使わずにCLIを作る方法があったら教えてください
mixとは何か
mixのhelpを見てみます。
$ mix --help
Mix is a build tool for Elixir
Usage: mix [task]
Examples:
mix - Invokes the default task (mix run) in a project
mix new PATH - Creates a new Elixir project at the given path
mix help - Lists all available tasks
mix help TASK - Prints documentation for a given task
The --help and --version options can be given instead of a task for usage and versioning information.
まま訳すと、
- mixはElixirのビルドツール
- 「mix」でデフォルトのtaskを実行する
- 「mix new PATH」で、projectを作る
- 「mix help」で、すべてのtaskを一覧する
- 「mix TASK」で、taskのドキュメントを出力する
ということみたいです。ざくざく進みたいので、早速mix newを実行してみます。
mix new
mix newでechoプロジェクトを作ります。
$ mix new echo
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/echo.ex
* creating test
* creating test/test_helper.exs
* creating test/echo2_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd echo
mix test # mixのTASKにはtestがあるということが分かります。
$ cd echo
$ tree -a
.
├── .formatter.exs
├── .gitignore
├── README.md
├── lib
│ └── echo.ex # echoモジュール
├── mix.exs
└── test # テストがデフォルトで組み込まれているようです。
├── echo_test.exs # テストのスクリプト
└── test_helper.exs # テストのヘルパー
次にecho.exを見てみます。
$ cat lib/echo.ex
defmodule Echo do
@moduledoc """
Documentation for Echo.
"""
@doc """
Hello world.
## Examples
iex> Echo.hello()
:world
"""
def hello do
:world
IO.puts "hello" # 追加!!!
end
end
Echoモジュールが定義されており、hello関数があります。
※出力させたいので、一行追加しています。
実行してみましょう。
$ mix run -e 'Echo.hello()' # mix run help または プログラミングElixirのp.136 参照
Compiling 1 files (.ex)
Generated echo app
hello # 出力されました。
echoコマンドの実装
echoコマンド作るには以下を行う必要があります。
- 「引数をうけたら、それをそのまま標準出力に吐く」ロジックを実装する
- それを実行できるファイルを作る
それを行う上で分かっていないことは以下です。
- echoコマンド用のロジックはどこで実装すべきか
- 実行ファイルをどのように作るか、その引数はどのようにロジックに渡されるか
順番に解決しましょう。
どこで実装すべきか
プログラミングElixirのp.133から抜粋すると(IssuesをEchoに置換しています)
Elixirには規約がある。lib/ディレクトリの中に、プロジェクトと同じ名前のサブディレクトリを作る(つまり、lib/echo/を作る。)。このディレクトリは、アプリケーションの主なソースコードが、一つのモジュールごとに一つのファイルとしておかれる。それぞれのモジュールは、Echoモジュールの中にネームスペースを確保することになる。つまり、モジュールの名前は、ディレクトリ名に対応する。
今回の場合、作りたいモジュールは、Echo.CLI、つまりEchoモジュールの下に入れ子になったCLIモジュールだ。これをディレクトリ構造に反映して、cli.exをlib/echoディレクトリに置こう。
※この規約に関してWEB上のドキュメントを探しましたが見つけることはできませんでした。
規約ということなので以下に実装します。
├── lib
│ ├── echo
│ │ └── cli.ex
│ └── echo.ex
~
実行ファイルと引数について
調べると、実行ファイルを作るには「mix escript.build」を使うようです。
プログラミングElixir p.149参照
実行前に以下を追加します。
- mix.exsにescriptの設定を追加します。
- cli.exにmain関数
defmodule Echo.MixProject do
use Mix.Project
def project do
[
app: :echo,
version: "0.1.0",
elixir: "~> 1.9",
start_permanent: Mix.env() == :prod,
deps: deps(),
escript: escript() # 追加!!!
]
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
# 追加!!!
def escript do
[main_module: Echo.CLI]
end
end
defmodule Echo.CLI do
# main関数の引数にコマンドライン呼び出し時の引数が渡るようです。
# 確認しましょう。
def main(argv) do
IO.inspect argv
end
end
実行ファイルを作成してみます。
$ mix escript.build
Compiling 1 file (.ex)
Generated escript echo with MIX_ENV=dev
$ ls -lht
合計 1.1M
-rwxrwxr-x 1 pojiro pojiro 1.1M 11月 7 21:08 echo # できました
drwxrwxr-x 3 pojiro pojiro 4.0K 11月 7 16:41 lib
-rw-rw-r-- 1 pojiro pojiro 643 11月 7 15:36 mix.exs
drwxrwxr-x 2 pojiro pojiro 4.0K 11月 7 15:20 test
drwxrwxr-x 4 pojiro pojiro 4.0K 11月 7 15:12 _build
-rw-rw-r-- 1 pojiro pojiro 482 11月 7 14:01 README.md
引数を渡して実行してみます。
$ ./echo test test
["test", "test"]
コマンドライン呼び出しの引数は文字列のリストとして渡るようです。
cli.exを修正しましょう。
defmodule Echo.CLI do
def main(argv) do
argv |> Enum.join(" ") |> IO.puts
end
end
確認します。
$ mix escript.build
Compiling 1 file (.ex)
Generated escript echo with MIX_ENV=dev
$ ./echo test test
test test # ばっちり
いきなり、echoコマンドが完成しました!やった!
まとめ
分かったこと
CLIをつくるためには最低限以下を知れば十分ということを理解しました。
- mix newでプロジェクトをつくる
- lib/Module/cil.exにコマンドラインの引数を受けるmain関数と動作ロジックを実装する
- mix escript.buildを実行し、実行ファイルを作る
取り扱わなかったこと
echoコマンドを作ることを優先するために以下をあえて取り扱いませんでした。
- 引数のparseライブラリ、OptionParser
- テストの実装、実行するmix test
わからなかったこと
残念ながら以下が追いきれませんでした。教えていただけると嬉しいです。
- mixを使わない実行ファイルの作成方法が別にあるのか
- echo.exはどのような機能を実装すべきファイルなのか
- mixのプロジェクト構造の規約のドキュメントはあるのか
おわり
「いいね」よろしくお願いします。