心を整えて、コードを整える。~状況に応じたSwiftFormatの使い方をする為に ~

SwiftFormatを使ってコードを自動フォーマットさせるにあたって

- 落ち着いて取り入れる
- 考慮漏れを発生させない

この2点に重点を置いて、焦らず進められるように内容をまとめました。

##導入

###CocoaPodsを使ってインストール

```
pod 'SwiftFormat/CLI'
```

###Xcodeで動かしてみる
実際にXocdeで使って、コンパイル毎にSwiftFormatを動かしてみます。

Xocdeでプロジェクトファイルを開いて、Build PhasesにSwiftFormatのPhaseを作ります。
Build Phasesに追加することで、コンパイルのタイミングでSwiftFormatによるコードのフォーマットが行われます。

####気をつけること
Compile Sourcesの前にSwiftFormatを動かすPhaseを作ります。

これは、SwiftFormatでコードを整形 > 整形された状態でコンパイルとする為です。

####実際に追加してみる
プロジェクトのBuild Phase > +ボタン > New Run Script Phase
![開く.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368129/9db6d346-28fd-17d2-782d-c3b9afd8afda.png)

追加したRun Scriptに以下を追加します。

```
${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat
```

![SwiftFormatRUN.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368129/4433894c-1621-adde-ae08-125e78151479.png)

これでコンパイル毎に、自動でフォーマットされるようになります。

##オプションを使用する

このままの状態ですと次の不都合が生じる為、オプションの内容を確認しながら設定を追加します。

- Podsのソースもチェックされてしまう
- 使用しているSwiftのバージョンで使えるはずの一部のルールが反映されない
- 反映させると不都合なルールがある

###Podsのソースはチェックさせない

オプション`--exclude` を使用することで、チェック対象を一部無効にすることが可能です。

> The --exclude option takes a comma-delimited list of file or directory paths to exclude from formatting. Excluded paths are relative to the config file containing the --exclude command. The excluded paths can include wildcards, specified using Unix "Glob" syntax, as documented below.[^1]



直接触ることのないPodsのソースなどを除外する場合は、`--exclude`を使用してチェック対象から外すことができます。

```:オプションの使用例
--exclude Pods
```


###使用しているSwiftバージョンで使える新しいルールを反映させる

Swiftのバージョンを指定していない場合に、そのバージョンで使用できる一部のルールが適用されないとの記載があります。

>Most SwiftFormat rules are version-agnostic, but some are applicable only to newer Swift versions. These rules will be disabled automatically if the Swift version is not specified, so to make sure that the full functionality is available you should specify the version of Swift that is used by your project.[^2]

その為、使用中のSwiftのバージョンを指定していない状態ですと、本来適用されるはずのルールが考慮されない状態となってしまいます。

実際に試してみたところ、不要なreturnを自動で消すルール `redundantReturn` がこれに該当していました。

```diff:redundantReturnのルールが有効の場合
- array.filter { return $0.foo == bar }
+ array.filter { $0.foo == bar }
```
有効な場合には、一つしか式がない場合に省略されるはずのreturnが、バージョンを指定しない状態ではそのままになっていました。

その為、以下の対応を取ります。

#####Xcodeで使用しているSwiftのバージョンを確認

```
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -version
```

```:出力結果
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
```

#####適用するSwiftのバージョンの指定

>Use the --swiftversion argument to enable additional rules specific to later Swift versions.[^3]

確認したバージョンを `--swiftversion` の引数に指定することで、そのバージョンで使える新しいルールも自動で有効となります。

```:オプションの使用例
--swiftversion 5.1.3
```

###SwiftFormatのルールを一部無効にする
SwiftFormatには、様々なルールがあります。
詳細は以下にまとめられており、かなり多くのルールがあることがわかります。
https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md

こちらのたくさんのルールは、`--disable` オプションを使用することで一部だけ無効にすることが可能です。

> You can disable rules individually using --disable followed by a list of one[^4]


例えば、未使用の引数を `_` へ置き換えるルールの `unusedArguments`が有効となっている場合。

```diff:unusedArgumentsのルールが有効の場合
- func foo(bar: String, baz: String) {
    print("Hello \(baz)")
    // print("Hello \(bar)")
  }
+ func foo(bar _: String, baz: String) {
    print("Hello \(baz)")
    // print("Hello \(bar)")
  }
```

`unusedArguments`が有効な状態ですと、処理をコメントアウトして確認する度に引数が置き換えられてしまいます。
これにより、作業が進めづらい場合などに`--disable`使用して一部のルールだけ無効にすることができます。


```:オプションの使用例
--disable unusedArguments
```

これらのオプションを全て適用するとRun Scriptの内容は、次のようになります。

```
"${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat" . --exclude Pods --swiftversion 5.1.3 --disable unusedArguments
```

[^1]: 引用元：https://github.com/nicklockwood/SwiftFormat/blob/master/README.md#config-file
[^2]: 引用元：https://github.com/nicklockwood/SwiftFormat/blob/master/README.md#swift-version
[^3]: 引用元：https://github.com/nicklockwood/SwiftFormat/blob/master/README.md#faq
[^4]: 引用元：https://github.com/nicklockwood/SwiftFormat/blob/master/README.md#rules