RuboCop とスタイルガイドを組み合わせて活用する




RuboCop は、Ruby の為のスタイルチェッカであり、[bbatsov/ruby-style-guide](https://github.com/bbatsov/ruby-style-guide) をベースにルールが作られています。
この記事では RuboCop と Ruby Style Guide を組み合わせて有効活用する方法について紹介します。

TL;DR
============

- RuboCop のメッセージだけでは足りていない情報が、[Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) で補完できる。
- `.rubocop.yml`に以下を追記するだけで、Ruby Style Guide と RuboCop を連携できる。

```yaml
AllCops:
  DisplayStyleGuide: true
  # 日本語を使いたい場合は以下の一行も追加
  StyleGuideBaseURL: https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md
```


RuboCop のメッセージが不親切
======================


何故 RuboCop をスタイルガイドと組み合わせて使用することが必要なのでしょうか？
その理由のひとつに、RuboCop のデフォルトのメッセージが不親切、ということが上げられます。

以下のコードを例に考えてみましょう。


```test.rb
for x in [a, b, c] do
  something(x)
end
```

このコードに対して RuboCop を実行すると、以下のように「`for`文の代わりに`each`を使用するべき」という警告が出ます。

```bash
$ rubocop
Inspecting 1 file
C

Offenses:

test.rb:1:1: C: Prefer each over for.
for x in [a, b, c] do
^^^

1 file inspected, 1 offense detected
```

このメッセージからは「`each`を使用すべき」ということはわかりますが、それ以上の情報は含まれていません。
つまり、「なぜ`for`より`each`を使用すべきなのか」「`for`と`each`の違いは何なのか」と言った情報は、これだけでは得ることが出来ません。
そのため、このメッセージを見た人は自分で`for`の意味を調べるか、ただ盲目的に RuboCop の指摘に従うしかありません(そしてこれは最悪です)。


このような不親切なメッセージは、この`for`に関するルール以外でも多く見られます。
では、どうしたら RuboCop のメッセージからより詳細な情報を得ることができるでしょうか？



Ruby Style Guide を参照する
========================


冒頭にも述べたとおり、RuboCop は [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) のスタイルをベースに作られています。
そのため(特に Style 系のルールに関しては) Ruby Style Guide にそのスタイルに関する詳細な記述が存在することが多いです。

例えば、先程の例である`for`に関するルールに関しても、その詳細な記述がスタイルガイドに存在します。


> * <a name="no-for-loops"></a>
>     Do not use `for`, unless you know exactly why. Most of the time iterators
>     should be used instead. `for` is implemented in terms of `each` (so you're
>     adding a level of indirection), but with a twist&mdash;`for` doesn't
>     introduce a new scope (unlike `each`) and variables defined in its block
>     will be visible outside it.
> <sup>[[link](#no-for-loops)]</sup>
> 
>   ```Ruby
>   arr = [1, 2, 3]
> 
>   # bad
>   for elem in arr do
>     puts elem
>   end
> 
>   # note that elem is accessible outside of the for loop
>   elem # => 3
> 
>   # good
>   arr.each { |elem| puts elem }
> 
>   # elem is not accessible outside each's block
>   elem # => NameError: undefined local variable or method `elem'
>   ```
>
> https://github.com/bbatsov/ruby-style-guide#no-for-loops


これを参照することで、RuboCop のメッセージだけでは得られなかった「何故`each`を使用すべきなのか」を知ることが出来ます。



ですが、RuboCop に指摘を受ける度にスタイルガイドを探すのは大変です。
もっといい方法はないのでしょうか？



RuboCop にスタイルガイドの URL を出力させる
=================

解決策として、RuboCop にスタイルガイドの URL を出力されることが出来ます。

先程のコードに対して、もう一度 RuboCop を走らせてみましょう。今度は`--display-style-guide`オプション付きで RuboCop を実行してみます。

```bash
Inspecting 1 file
C

Offenses:

test.rb:1:1: C: Prefer each over for. (https://github.com/bbatsov/ruby-style-guide#no-for-loops)
for x in [a, b, c] do
^^^

1 file inspected, 1 offense detected
```

先程と違い URL が出力されていることがわかると思います。
この URL は指摘に対応するスタイルガイドの項目へのリンクです。

このように`--display-style-guide`オプションを付与して RuboCop を実行すると、指摘に対してのより詳細な情報を手軽に知ることが出来るようになります。



また、毎回このオプションを指定するのは大変です。
`.rubocop.yml`に以下の記述を追加することで、オプションの指定を省略することが出来ます。

```yaml
AllCops:
  DisplayStyleGuide: true
```


日本語でスタイルガイドを読む
==========

ところで、先程上げたスタイルガイドは英語で書かれています。
英語に自信のない方など、日本語で書かれたスタイルガイドを読めたほうが嬉しいという方も多いのではないでしょうか？



このスタイルガイドは多言語に翻訳されていて、勿論日本語にも翻訳がなされています。
日本語のスタイルガイドはこちらから読むことが可能です。 https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md

例えば、先程の`for`の例は以下のように翻訳されています。


> * <a name="no-for-loops"></a>
>   `for`は、どうしても使わなければいけない明確な理由が明言できる人以外は、使ってはいけません。
>   多くの場合は代わりにイテレータを使うべきです。
>   `for`は`each`をつかって実装されています(だから、より遠回しです)が、
>   `for`は(`each`と違い)新しいスコープを導入せず、
>   そのブロック内で定義された変数は、ブロックの外からも見えます。
> <sup>[[link](#no-for-loops)]</sup>
> 
>   ```Ruby
>   arr = [1, 2, 3]
> 
>   # 悪い例
>   for elem in arr do
>     puts elem
>   end
> 
>   # elemはループの外からも参照できることに注意しましょう
>   elem # => 3
> 
>   # 良い例
>   arr.each { |elem| puts elem }
> 
>   # elemはeachブロックの外からは参照できません
>   elem # => NameError: undefined local variable or method `elem'
>   ```
>
> https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md#no-for-loops




また、この翻訳されたスタイルガイドの URLの を RuboCop に出力させることも可能です。
先程の`.rubocop.yml`に以下のように1行追記して下さい。

```yaml
AllCops:
  DisplayStyleGuide: true
  StyleGuideBaseURL: https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md
```

この設定を適用した上で RuboCop を実行することで、以下のような出力が得られます。

```bash
Inspecting 1 file
C

Offenses:

test.rb:1:1: C: Prefer each over for. (https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md#no-for-loops)
for x in [a, b, c] do
^^^

1 file inspected, 1 offense detected
```

URL が日本語のものになっていますね。


まとめ
==========

このように RuboCop を少し設定するだけで、RuboCop からの指摘をより有意義なものとすることが出来ます。
RuboCop からされた指摘をなんとなくで直していた方や、「言ってることは分かるけど理由くらい言ってよ…」と思っていた方は、是非この設定をお試しください。