scalafmtでScalaコードを整える

はじめに

最近は毎週のドラマ「サ道」 が楽しみな佐々木です。 サウナで整ったらコードも整えたいということで最近使い始めたscalafmtについて簡単に紹介します。

scalafmtとは

他の言語にもあるようなソースコードのフォーマッタです。 公式サイトには次の2つのフレーズが掲げられています。

Focus on what matters

Spend more time discussing important issues in code review and less time on code style. Scalafmt formats code so that it looks consistent between people on your team.

Integrated with your toolchain

Run scalafmt from your editor, build tool or terminal. Scalafmt has integrations with IntelliJ, sbt, Maven, Gradle and Mill.

やりたいこと

で、今回はこの3つを設定して整いたいと思います。

  • IntelliJでソースコードファイルの保存時にフォーマットする
  • SBTプラグインを使ってコマンドラインからフォーマットする
  • 同じくSBTプラグインを使ってCircleCI上でフォーマットのチェックをする

設定ファイルを作る

まずはフォーマットの設定を定めます。プロジェクトルートに.scalafmt.conf ファイルを作り、フォーマットの詳細を記述していきます。 各設定の詳細はこちら

とりあえず中身はドキュメントを参考にこんな感じにします。 ( :1行目の version=... の設定はドキュメントにはありませんが後述のSBTプラグインの実行時に必要なので指定しています)

version=2.0.0-RC5

align = more    // For pretty alignment.
maxColumn = 100 // For my wide 30" display.

IntelliJでソースコードファイルの保存時にフォーマットする

設定ファイルができたらIntellijでフォーマッタを使うように設定します。 IntelliJでscalafmtを使うにはプラグイン をインストールします。

プラグインリポジトリで上記のプラグインをインストールしたら下記の設定画面の「Format on file save」をONにします。

SBTプラグインを使ってコマンドラインからフォーマットする

次にSBTプラグインを導入します。

使っているSBTのバージョンによって以下のどちらかを project/plugins.sbt に追記します。

// In project/plugins.sbt. Note, does not support sbt 0.13, only sbt 1.x.
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.0.0")
// or
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.5.1") // before 1.6.0-RC4 

プラグインを追加したら下記の代表的なsbtコマンドでフォーマットやチェックを行えます。

  • scalafmt: ソースコード(main)をフォーマットする
  • test:scalafmt: テストコード(test)をフォーマットする
  • scalafmtCheck: ソースコードがフォーマッタのルールに従っているかチェックする
  • scalafmtSbt: *.sbt および project/*.scala ファイルをフォーマットする
  • scalafmtSbtCheck:  *.sbt および project/*.scala ファイルのフォーマットをチェックする

SBTプラグインを使ってCircleCI上でフォーマットのチェックをする

フォーマットに従っていないコードはCIでエラーを起こしてチェックします。 CircleCIの場合はstepsに下記のようなSBTコマンドを実行するステップを追加します。

- run:
  name: check code format
  command: cat /dev/null | sbt scalafmtCheck test:scalafmtCheck scalafmtSbtCheck

実際に実行してみるとこんな感じになります

(例) 1ファイルがフォーマットされていなくてエラー

[info] Loading settings for project global-plugins from idea.sbt ...
[info] Loading global plugins from /Users/sasaki.kazuhiro/.sbt/1.0/plugins
[info] Loading settings for project scalafmt-example-build from plugins.sbt ...
[info] Loading project definition from /Users/sasaki.kazuhiro/src/github.com/cm-kazup0n/scalafmt-example/project
[info] Loading settings for project scalafmt-example from build.sbt ...
[info] Set current project to scalafmt-example (in build file:/Users/sasaki.kazuhiro/src/github.com/cm-kazup0n/scalafmt-example/)
[info] Checking 3 Scala sources...
[warn] /Users/sasaki.kazuhiro/src/github.com/cm-kazup0n/scalafmt-example/src/main/scala/app/Main.scala isn't formatted properly!
[error] 1 files must be formatted
[error] (Compile / scalafmtCheck) 1 files must be formatted
[error] Total time: 3 s, completed 2019/08/15 19:11:11

OKの場合

[info] Loading settings for project global-plugins from idea.sbt ...
[info] Loading global plugins from /Users/sasaki.kazuhiro/.sbt/1.0/plugins
[info] Loading settings for project scalafmt-example-build from plugins.sbt ...
[info] Loading project definition from /Users/sasaki.kazuhiro/src/github.com/cm-kazup0n/scalafmt-example/project
[info] Loading settings for project scalafmt-example from build.sbt ...
[info] Set current project to scalafmt-example (in build file:/Users/sasaki.kazuhiro/src/github.com/cm-kazup0n/scalafmt-example/)
[info] Checking 3 Scala sources...
[success] Total time: 2 s, completed 2019/08/15 19:12:06
[success] Total time: 0 s, completed 2019/08/15 19:12:07
[success] Total time: 0 s, completed 2019/08/15 19:12:07

まとめ

体と心はサウナで、コードはフォーマッタで整えましょう。