Elixir1.6のformatterの挙動を観察してみた

Elixir1.6のformatterを使っているという記事を見かけたので羨ましくなって試してみた。

[サイボウズLiveを作る](http://alphabrend.hatenablog.com/archive/category/%E3%82%B5%E3%82%A4%E3%83%9C%E3%82%A6%E3%82%BALive%E3%82%92%E4%BD%9C%E3%82%8B)で書いたコードを一括でformatterにかけてみた。今回対象にしたのはex, exsのみ。

### リストやマップが綺麗に

自動生成されたデフォルトのmix.exs等のコードは変なリストの書き方だったので改善された。自動生成されたモデルのひどいcastも全部修正される。ちなみにリストやマップの最後にカンマがある場合は削除される。

```elixir:before
    [mod: {Cybozulive.Application, []},
     applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,
                    :phoenix_ecto, :mariaex, :ueberauth_twitter, :arc_ecto, :timex]]
```

```elixir:after
    [
      mod: {Cybozulive.Application, []},
      applications: [
        :phoenix,
        :phoenix_pubsub,
        :phoenix_html,
        :cowboy,
        :logger,
        :gettext,
        :phoenix_ecto,
        :mariaex,
        :ueberauth_twitter,
        :arc_ecto,
        :timex
      ]
    ]
```

逆に１行で収まる場合は１行にしてくれる。

```elixir:before
  pubsub: [name: CybozuliveWeb.PubSub,
           adapter: Phoenix.PubSub.PG2]
```
```elixir:after
  pubsub: [name: CybozuliveWeb.PubSub, adapter: Phoenix.PubSub.PG2]
```

### スペースの桁揃え削除

誰かのこだわりのスペース揃えが削除された。

```elixir:before
  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_),     do: ["lib"]
```
```elixir:after
  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]
```

### Ecto

通常のコードでは括弧をつけるのが一般的だが、schemaだけ無しで自動生成されてたみたいなので一通り追加されていた。routerも同様。

```elixir:before
    field :body, :string
```
```elixir:after
    field(:body, :string)
```

あとqueryも括弧有りに修正されている。Ectoのマニュアルも変わっていくのかな。

```elixir:before
    query = from g in Group,
      where: g.id == ^id and is_nil(g.deleted_at)
```
```elixir:after
    query = from(g in Group, where: g.id == ^id and is_nil(g.deleted_at))
```

長いやつ。これはどちらかというと分割していった方が綺麗かもしれないので、自分でちゃんと整えたほうがよいかもしれない。

```elixir:before
    query = from i in Invitation,
      where: i.user_id == ^user.id and i.group_id == ^group.id and is_nil(i.closed_at) and is_nil(i.deleted_at)
```
```elixir:before
    query =
      from(
        i in Invitation,
        where:
          i.user_id == ^user.id and i.group_id == ^group.id and is_nil(i.closed_at) and
            is_nil(i.deleted_at)
      )
```

### 長いif文

演算子は行末。なぜ２行目がスペース５つなのかはよくわからない。

```elixir:before
    if (is_nil(board_topic.group.deleted_at)
      && Enum.any?(conn.assigns.joining_groups, fn(group) -> group.id == board_topic.group_id end)) do
```
```elixir:after
    if is_nil(board_topic.group.deleted_at) &&
         Enum.any?(conn.assigns.joining_groups, fn group -> group.id == board_topic.group_id end) do
```

### 長いif & else

無理やり１文で書いて長くなったif & else

```elixir:before
    if schedule.schedule_category, do: schedule.schedule_category.bg_color, else: schedule.bg_color
```
```elixir:after
    if schedule.schedule_category,
      do: schedule.schedule_category.bg_color,
      else: schedule.bg_color
```

これも1文で書けないなら普通に下記の方が良さそう。

```elixir
    if schedule.schedule_category do
      schedule.schedule_category.bg_color
    else
      schedule.bg_color
    end
```

### 空行が入る

合間で空行を入れて見やすくしたいらしい。condとかも。

```elixir
    case Repo.update(changeset) do
      {:ok, board_post} ->
        conn
        |> put_flash(:info, "Board post updated successfully.")
        |> redirect(to: board_post_path(conn, :show, nil, board_post))

      {:error, changeset} ->
        render(conn, "edit.html", board_post: board_post, changeset: changeset)
    end
```

とか

```elixir
    date_text = Timex.format!(date, "{YYYY}-{0M}-{0D}")

    if time do
```

逆に連続した空行は１行まで削られる。

### 無理やり１行にした条件はだめ

```elixir:before
      nil -> attrs
```
```elixir:after
      nil ->
        attrs

```

### 長いrenderが複数行に

これは自分でちゃんとassignでパイプした方がいい。

```elixir:before
    render(conn, "index.html", board_posts: board_posts, board_topic: board_topic, changeset: changeset)
```
```elixir:after
    render(
      conn,
      "index.html",
      board_posts: board_posts,
      board_topic: board_topic,
      changeset: changeset
    )
```

### パイプラインの戻り値

変数に入れる時は代入文を１行にして後はインデント

```elixir:before
    board_topics = Repo.all(query)
    |> Repo.preload(:user)
    |> Repo.preload(:board_category)
```
```elixir:after
    board_topics =
      Repo.all(query)
      |> Repo.preload(:user)
      |> Repo.preload(:board_category)
```

パイプラインでなくても同様

```elixir:before
    result = Repo.transaction(fn ->
      Groups.update_invitation!(invitation, invitation_params)
      Groups.create_group_user!(invitation.user, group)
    end)
```
```elixir:after
    result =
      Repo.transaction(fn ->
        Groups.update_invitation!(invitation, invitation_params)
        Groups.create_group_user!(invitation.user, group)
      end)
```

### 括弧なしの関数呼び出しはだめ

いくつも修正されてるからどうもだめっぽい。まあたしかにRailsでもそうだけど関数なのかどうかぱっとみよく分からん。

```elixir:before
    invitation_params = %{"deleted_at" => Timex.now}
```
```elixir:after
    invitation_params = %{"deleted_at" => Timex.now()}
```

### まとめ

* Elixir & Phoenixの場合、いわゆるコーディング規約みたいなのがどこを参考にすればよいかよくわからないところがあったので、非常に助かる。
* useとかaliasの順番が決まっているとかどこかで見たような気がするが、そういうのは特に変更されないっぽい。
* １行何桁までOKなのか試したら、104桁までOKだった。どういう基準だろ。ちなみにdef文1パターンしか調べてないので他は不明。
* 個人的には勝手に１行にしてくれるのが好き。