プログラミングElixir第13章「プログラムを構成する」(〜13.6まで)をやってみる

この記事は、勉強会（[Elixir女子部「エリジョ」 プログラミングElixir「第13章プロジェクトを構成する」しよう！](https://elijo.connpass.com/event/221551/)）の予習/復習として書いたものです。
対象の書籍は[プログラミングElixir](https://www.ohmsha.co.jp/book/9784274226373/)です。

## プログラミングElixir第13章「プログラムを構成する」で扱うこと
* プロジェクトの構造
* Mixビルドツール
* ExUnitテストフレームワーク
* ドキュメンテーション

第13章では、ElixitのビルドツールMixを見ていくことになります。
Mixのディレクトリ構造を調べ、外部依存の管理方法を見て、最後にはExUnitで実際のコードのテストを書いていきます。

本記事のバージョンは下記で進めています。

```
$ mix --version
Erlang/OTP 24 [erts-12.0.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit] [dtrace]

Mix 1.12.2 (compiled with Erlang/OTP 24)
```

```
elixir --version
Erlang/OTP 24 [erts-12.0.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit] [dtrace]

Elixir 1.12.2 (compiled with Erlang/OTP 24)
```

### ソースコードがDLできるぞ！

Pragmatic Bookshelfで原著（Programming Elixir 1.6）購入ページからソースコードがZipでダウンロードできます。
https://pragprog.com/titles/elixir16/programming-elixir-1-6/

## 13.1 プロジェクト:GithubからIssuesを取得

GETリクエストで`https://api.github.com/repos/user/project/issues`に発行すると
GithubからIssuesを取得できます。

これを整形して、並び替え、古い順にn個フィルタして、結果をテーブルとして出力できるようにしていきます。

## 13.2 ステップ1：Mixを使って新しいプロジェクトを作る

### 新しいプロジェクトを作る

`mix new`で新規Elixirプロジェクトを作成します。

```
$ mix new issues
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/issues.ex
* creating test
* creating test/test_helper.exs
* creating test/issues_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd issues
    mix test

Run "mix help" for more commands.
```

作成されたディレクトリのファイル構成は下記のとおり。

```
$ tree issues/
issues/
├── README.md
├── lib
│   └── issues.ex
├── mix.exs
└── test
    ├── issues_test.exs
    └── test_helper.exs
```

プログラミングElixir本文を読む限りconfigディレクトリが出来るはずなんだけど、あれ、できないな？？

※Elixir1.9の変更で`mix new`でconfigファイルを作らないようになったそうです。
参照
https://dev.to/gumi/elixir-elixir-1-9-1dmp
http://blog.plataformatec.com.br/2019/04/whats-new-in-elixir-apr-19/

さて、作成されるファイルのいくつかの役割等は次のとおりです。

* .formatter.exs
  * ソースコードのフォーマッターに使われる設定ファイル
* config/
  * アプリケーション特有の設定を書くことになる場所
* lib/
  * プロジェクトのソースコードが置かれる場所
  * Mixはトップレベルのモジュールを既に追加している（今回はissues.exx）
* mix.exs
　　　* プロジェクトの設定を含むソースファイル。プロジェクトが進むにつれて設定を追加していくことになる。
* test/
  * テストを置く場所。プロジェクト作成時にissuesモジュールのユニットテストのためのヘルパーファイルとスタブが作られる。

### 13.3 変換：コマンドライン解析

コマンドラインオプションの取り扱いをプログラムのメイン部分に結びつけるのは避けたいので、
ユーザーの入力したものとプログラムがやろうとすることを橋渡しする、独立したモジュールを書きます。
規約で、このモジュールはProject.Cli(今回はIssues.CLI)と呼ばれます。

このモジュールのエントリポイントはrunという、コマンドライン引数の配列を一つ受け取る関数（これも規約の一部）です。

issuesモジュールの下に入れ子になったCLIモジュールを作ります。（lib/issues/cli.ex)

```
lib
├── issues
│   └── cli.ex
└── issues.ex
```

lib/ディレクトリの中にプロジェクトと同じ名前のサブディレクトリを作ります（lib/issues/)。
このディレクトリは、アプリケーションの主なソースコードが1つのモジュールごとに1つのファイルとして置かれます。これはElixirの規約です。

lib/issues/cli.exは書籍本文のコードをそのまま書いていきます。
ここではrun関数と、コマンドラインから受け取った引数をパースするparse_argv関数を記述していきます。

### 13.4 基本的なテストを書く

ElixirにはExUnitというテストフレームワークがあります。
プロジェクト作成時に生成されたtest/issues_test.exsは、これから書くすべてのテストファイルのテンプレートになります。
書籍のサンプルコードを見ながら、CLIモジュールのテスト(test/cli_test.exs)を書いていきます。
※このテストファイルの置き方は簡易的なものなので、実際の案件だとNGだそうです。

```
$ mix test
Compiling 1 file (.ex)
......

Finished in 0.05 seconds (0.00s async, 0.05s sync)
2 doctests, 4 tests, 0 failures
```

`mix test`でテストタスクを実行します。
４つあるテストのうち１つは失敗するようになっているので、本文を見ながら修正して再度テストを実行します。
次は４つすべてテストが通るようになります。

### 13.5 リファクタリング：大きな関数注意報

最初に追加したparse_argv関数は、条件ロジックを含んでおり、また関数内のコードが長いらしい。
本文のとおりソースコードを書き換え、テストを走らせます。

### 13.6 変換：Githubからの取得

run関数からprocess関数を呼ぶように拡張します。
process関数にはparse_argv関数の引数の返り値を引数として渡します。
流れを明確にするためにElixirのパイプ演算子を使うとよいそうです。

```elixir:issues/lib/issues/cli.ex
def run(argv)
  argv
  |> parse_argv
  |> process
end
```

本文のとおりソースコードを書き換えます。

## 感想

これまでの基礎周りの応用編といった章なので、この章から始めるのも良いと思います。
第13章は範囲が広く、勉強会1回の時間ではおさまりきらなかったので、次回に続きます。

続きの勉強会
[Elixir女子部「エリジョ」 プログラミングElixir「第13章プロジェクトを構成する」おかわり](https://elijo.connpass.com/event/224148/)