RuboCop は、Ruby の為のスタイルチェッカであり、bbatsov/ruby-style-guide をベースにルールが作られています。
この記事では RuboCop と Ruby Style Guide を組み合わせて有効活用する方法について紹介します。
TL;DR
- RuboCop のメッセージだけでは足りていない情報が、Ruby Style Guide で補完できる。
-
.rubocop.yml
に以下を追記するだけで、Ruby Style Guide と RuboCop を連携できる。
AllCops:
DisplayStyleGuide: true
# 日本語を使いたい場合は以下の一行も追加
StyleGuideBaseURL: https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md
RuboCop のメッセージが不親切
何故 RuboCop をスタイルガイドと組み合わせて使用することが必要なのでしょうか?
その理由のひとつに、RuboCop のデフォルトのメッセージが不親切、ということが上げられます。
以下のコードを例に考えてみましょう。
for x in [a, b, c] do
something(x)
end
このコードに対して RuboCop を実行すると、以下のように「for
文の代わりにeach
を使用するべき」という警告が出ます。
$ 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 のスタイルをベースに作られています。
そのため(特に Style 系のルールに関しては) Ruby Style Guide にそのスタイルに関する詳細な記述が存在することが多いです。
例えば、先程の例であるfor
に関するルールに関しても、その詳細な記述がスタイルガイドに存在します。
Do not usefor
, unless you know exactly why. Most of the time iterators
should be used instead.for
is implemented in terms ofeach
(so you're
adding a level of indirection), but with a twist—for
doesn't
introduce a new scope (unlikeeach
) and variables defined in its block
will be visible outside it.
[link]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'
これを参照することで、RuboCop のメッセージだけでは得られなかった「何故each
を使用すべきなのか」を知ることが出来ます。
ですが、RuboCop に指摘を受ける度にスタイルガイドを探すのは大変です。
もっといい方法はないのでしょうか?
RuboCop にスタイルガイドの URL を出力させる
解決策として、RuboCop にスタイルガイドの URL を出力されることが出来ます。
先程のコードに対して、もう一度 RuboCop を走らせてみましょう。今度は--display-style-guide
オプション付きで RuboCop を実行してみます。
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
に以下の記述を追加することで、オプションの指定を省略することが出来ます。
AllCops:
DisplayStyleGuide: true
日本語でスタイルガイドを読む
ところで、先程上げたスタイルガイドは英語で書かれています。
英語に自信のない方など、日本語で書かれたスタイルガイドを読めたほうが嬉しいという方も多いのではないでしょうか?
このスタイルガイドは多言語に翻訳されていて、勿論日本語にも翻訳がなされています。
日本語のスタイルガイドはこちらから読むことが可能です。 https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md
例えば、先程のfor
の例は以下のように翻訳されています。
for
は、どうしても使わなければいけない明確な理由が明言できる人以外は、使ってはいけません。
多くの場合は代わりにイテレータを使うべきです。
for
はeach
をつかって実装されています(だから、より遠回しです)が、
for
は(each
と違い)新しいスコープを導入せず、
そのブロック内で定義された変数は、ブロックの外からも見えます。
[link]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行追記して下さい。
AllCops:
DisplayStyleGuide: true
StyleGuideBaseURL: https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md
この設定を適用した上で RuboCop を実行することで、以下のような出力が得られます。
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 からされた指摘をなんとなくで直していた方や、「言ってることは分かるけど理由くらい言ってよ…」と思っていた方は、是非この設定をお試しください。