チーム内で Unity C# のフォーマットを揃える

[TECOTEC Advent Calendar 2017](https://qiita.com/advent-calendar/2017/tecotec) の 25 日目の記事です。

# はじめに
C# で Unity （に限らないですが）の開発をおこなう場合、チーム内でコーディングスタイルを定めていることでしょう。
しかし、時間の経過や人の入れ替わりにより、人によってコードがばらばらになってしまうことは良くある事と思います。

プロジェクト内で IDE を統一して設定ファイルを共有化する、という方法もあるかもしれません。
でも「エディタくらい自分の好きなものを使いたい！」「Unity だろうが Vim しか使わない！」という人も中にはいます（私です :raising_hand: ）。


そこで、現在のプロジェクトでは、[Artistic Style](http://astyle.sourceforge.net/) を使ってコーディングスタイルを統一しているので、その方法を紹介します。

# [Artistic Style](http://astyle.sourceforge.net/) とは

C, C++, C#, Java ソースコードのためのフリーで高速かつ小型の自動フォーマッタです。

オプションを引数与えるか、オプションファイルに記述することで様々なスタイルに自動整形することができます。

例えば、以下のようなコードがあったとします。

```c:fizzbuzz.c
#include <stdio.h>

int main(void)
{
  int i;
  for (i=1;i<=50;i++) {
    if (i%3 == 0 && i%5 == 0)
      printf("FizzBuzz\n");
    else if (i%3 == 0)
      printf("Fizz\n");
    else if (i%5 == 0)
      printf("Buzz\n");
    else
      printf("%d\n",i);
  }
  return 0;
}
```

このコードを整形します。

```
$ astyle --style=allman fizzbuzz.c
Formatted  fizzbuzz.c
```

```c:fizzbuzz.c
#include <stdio.h>

int main(void)
{
    int i;
    for (i=1; i<=50; i++)
    {
        if (i%3 == 0 && i%5 == 0)
            printf("FizzBuzz\n");
        else if (i%3 == 0)
            printf("Fizz\n");
        else if (i%5 == 0)
            printf("Buzz\n");
        else
            printf("%d\n",i);
    }
    return 0;
}
```

インデントが変更されたのと、 `for` のあとの `{` が改行されたことがわかると思います。

# チーム内でスタイルを統一する

## オプションファイルを共有する
チームのコーディングスタイルルールに合わせるように、オプションファイルを作成して、プロジェクトの Git リポジトリ内に保存します。

```:astyle_options_c
mode=c

# Allman スタイル
style=allman

# インデント
indent=spaces=4
indent-namespaces
indent-classes
indent-switches
indent-cases
indent-col1-comments
min-conditional-indent=0

# スペース
pad-header
pad-oper
pad-comma
unpad-paren

# ブラケット
add-brackets
keep-one-line-blocks
break-blocks
delete-empty-lines

# 改行コード
lineend=linux
```

このオプションで先程のファイルを整形すると以下のようになります。

```
astyle --options=astyle_options_c --suffix=none fizzbuzz.c
```

```c:fizzbuzz.c
#include <stdio.h>

int main(void)
{
    int i;

    for (i = 1; i <= 50; i++)
    {
        if (i % 3 == 0 && i % 5 == 0)
        {
            printf("FizzBuzz\n");
        }
        else if (i % 3 == 0)
        {
            printf("Fizz\n");
        }
        else if (i % 5 == 0)
        {
            printf("Buzz\n");
        }
        else
        {
            printf("%d\n", i);
        }
    }

    return 0;
}
```

## Git の pre-commit でチェックする

整形するのをわすれたままコミットしてしまうのを防ぐために、Git の pre-commit を利用して正しいコーディングスタイルになっているかをチェックします。

以下のような pre-commit をチームのメンバー全員が設定するようにします。

```bash:pre-commit
#!/bin/bash

files=`git diff --cached --diff-filter=ACMR --name-only  HEAD | grep -E "\.c$"`

result=0

for file in ${files}; do

    tmp=$(mktemp)

    astyle --options=astyle_options_c --formatted < "${file}" > ${tmp}

    if ! cmp -s "${file}" ${tmp}; then

        echo "error: ${file} does not follow the coding style"
        git --no-pager diff --no-index ${file} ${tmp}
        result=1

    fi

    rm ${tmp}

done

exit ${result}
```

元の `fizzbuzz.c` をコミットしようとすると以下のようなエラーがでてコミットできないようになります。

```
$ git commit
error: fizzbuzz.c does not follow the coding style
diff --git a/fizzbuzz.c b/var/folders/l7/s15s8xjj7xggkcs5g__dlk8r0000gn/T/tmp.p4g3MG3B
index b0b724f..ea273f6 100644
--- a/fizzbuzz.c
+++ b/var/folders/l7/s15s8xjj7xggkcs5g__dlk8r0000gn/T/tmp.p4g3MG3B
@@ -2,16 +2,27 @@

 int main(void)
 {
-  int i;
-  for (i=1;i<=50;i++) {
-    if (i%3 == 0 && i%5 == 0)
-      printf("FizzBuzz\n");
-    else if (i%3 == 0)
-      printf("Fizz\n");
-    else if (i%5 == 0)
-      printf("Buzz\n");
-    else
-      printf("%d\n",i);
-  }
-  return 0;
+    int i;
+
+    for (i = 1; i <= 50; i++)
+    {
+        if (i % 3 == 0 && i % 5 == 0)
+        {
+            printf("FizzBuzz\n");
+        }
+        else if (i % 3 == 0)
+        {
+            printf("Fizz\n");
+        }
+        else if (i % 5 == 0)
+        {
+            printf("Buzz\n");
+        }
+        else
+        {
+            printf("%d\n", i);
+        }
+    }
+
+    return 0;
 }
```

# （おまけ） Vim で保存時に整形する

ルールと違ったコードを書いてしまってコミット時に怒られたり、毎回コマンドを叩いて整形するのが煩わしいので、Vim でファイルの保存時に自動でコマンドを叩くようにします。

```vim:vimrc
augroup MyAutoCmd
  autocmd BufWritePost *.c silent :! astyle --options=astyle_options_c --suffix=none % 1>/dev/null 2>/dev/null
augroup END

```

![vim.gif](https://qiita-image-store.s3.amazonaws.com/0/68571/c02ad91c-14c5-ef02-56ab-74c32a4373c5.gif)

# まとめ

以上、 Artistic Style と Git hook を使って、コーディングスタイルをチーム内で統一する方法を紹介しました。
使用する言語によって整形ツールは様々あると思いますが、コマンドになっているツールを使用することで、同じように Git の hook と組み合わせて使うことができると思います。