RuboCopというRuby向けの静的解析ツールについてご紹介致します。
SideCIでも昨日からRuboCopによる自動コードレビュー機能がお使いになれるようになりました。ぜひこの機会にRuboCopをお試し頂ければと思います。
RuboCopについて、RuboCopのRails向けオプション、バグに繋がりやすい内容だけを検出するlintオプションなど、規約以外の部分で役に立つオプションについても紹介しておりますので、ぜひご一読下さい!
Table Of Contents
- RuboCopとは
- RuboCopを利用するメリット
- RuboCopのインストール
- RuboCopの基本的な使い方
-R(--rails)
オプション-l(--lint)
オプション.rubocop.yml
の書き方について.rubocop_todo.yml
の使い方-a(--auto-correct)
オプション.rubocop.yml
の例
RuboCopとは
RuboCopは、あなたのプロジェクトのrubyコードが「コーディング規約どおりに書かれているか」をチェックする静的コード解析ツールです。
デフォルトのコーディング規約はRuby style guideに基いています。
(日本語訳)
設定ファイル(.rubocop.yml
)を編集することにより、自分自身でコーディング規約を追加したり削除することができます。
RuboCopを利用するメリット
Rubocopの設定は.rubocop.yml
に集中するので、自然とプロジェクトのコーディング規約が明文化されます。
Rubocopを活用しコードをきれいに保つことで、瑣末な指摘が減り、レビューの効率化につながります。
RuboCopのインストール
RuboCopは、gemで提供されます。
Bundlerを利用する場合、Gemfileに
gem 'rubocop', require: false
を追加します。
railsのようなWEBアプリケーションの場合、
大抵はdevelopment環境だけで動かすことが多いと思われますので、以下のようで良いでしょう。
group 'development' do ... gem 'rubocop', require: false end
Gemfileを編集した後、
$ bundle
でインストールできます。
Bundlerを利用しない場合、$ gem install rubocop
でインストールできます。
RuboCopの基本的な使い方
これより先の説明は、以下のバージョンで動作確認しています。
- ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]
- rubocop 0.29.1
rubocop
コマンド
実行コマンドは以下のとおりです。
以下、Bundlerを利用している場合は適宜bundle exec
を先頭につけてください。
$ rubocop [options] [file1, file2, ...]
- プロジェクトの中のrubyファイルを全てチェックするには、単に以下のようにします。
$ rubocop
- ヘルプを参照するには、以下のようにします。
$ rubocop --help
rubocop
の実行~出力結果の解釈
例として、以下の様なrubyファイル(test.rb
)を準備します。
def badName if something test end end
このtest.rb
に対してRuboCopを実行します。
$ rubocop test.rb
出力は以下のようになります。
Inspecting 1 file W Offenses: test.rb:1:5: C: Use snake_case for method names. def badName ^^^^^^^ test.rb:2:3: C: Use a guard clause instead of wrapping the code inside a conditional expression. if something ^^ test.rb:2:3: C: Favor modifier if usage when having a single-line body. Another good alternative is the usage of control flow &&/||. if something ^^ test.rb:4:5: W: end at 4, 4 is not aligned with if at 2, 2 end ^^^ 1 file inspected, 4 offenses detected
上記の出力は、以下のように解釈できます。
-
1行目の
Inspecting 1 file
は、チェックしたrubyファイルの数を表しています。 -
2行目の
W
は、チェックしたrubyファイルごとに見つかった違反(Convention
,Warning
,Error
,Fatal
の順に深刻)で一番深刻なものを頭文字1文字で表します。
今回の例では4個の違反が見つかり、一番深刻なものはWarning
でしたので、その頭文字のW
が出力されています。 -
3行目以降は、各違反ごとに詳しい箇所(ファイル名:行箇所:列箇所)と違反内容が出力されています。
-
最後の行は、何個のファイルがチェックされ、何個の違反があったかが出力されています。
では、以下のように全ての違反内容を修正した場合の出力を見てみましょう。
def good_name test if something end
$ rubocop test.rb Inspecting 1 file . 1 file inspected, no offenses detected
no offenses detected
、つまりコーディング違反は0になりました。
-R(--rails)
オプション
railsプロジェクトの場合、実行時に-R
オプションをつけることで、
追加としてRails Cop(railsに特化したCop)が実行されます。
以下のrubyファイル(test.rb
)はRuboCopデフォルトではコーディング違反はありませんが、
def good_name puts 'test' if something end
これをrailsのapp/models
の下に配置し、-R
をつけて実行すると
$ rubocop -R app/models/test.rb Inspecting 1 file C Offenses: app/models/test.rb:2:3: C: Do not write to stdout. Use Rails' logger if you want to log. print 'test' if something ^^^^^ 1 file inspected, 1 offense detected
と、「標準出力ではなくRailsのロガーを使え」というRails特有の違反が出力されることがわかります。
Rails Copはgemのlib/rubocop/cop/rails以下に定義されていますので、内容についてはここを参照ください。
また、.rubocop.yml
内で
AllCops: RunRailsCops: true
とすることで、毎回-R
オプションを指定しているのと同様、常にRails Copを有効にできます。
-l(--lint)
オプション
RuboCopでのそれぞれのチェック規則(Cop)は以下の4つに分類されます。
- Style (スタイルについてのCop)
- Lint (誤りである可能性が高い部分やbad practiceを指摘するCop)
- Metrics (クラスの行数や1行の文字数などに関してのCop)
- Rails (Rails特有のCop)
-l
オプションは、このうちのLintのみをチェックします。
.rubocop.yml
の書き方について
プロジェクトのルートディレクトリに.rubocop.yml
という設定ファイルを配置すると、
RuboCopはこれを自動的に読み取ります。または、-c
オプションで任意の場所にあるymlファイルを設定ファイルとして指定することも可能です。
以下、.rubocop.yml
内における、代表的な書き方を説明します。
RuboCopの対象から除外するファイルを指定する
railsが自動的に生成するファイル(db/schema.rb
)や、vendor/bundle
以下に配置されるgemなどを、
RuboCopの対象から除外したい場合は、Exclude:
を利用します。
例えばdb/schema.rb
というファイルをRuboCopの対象から外す場合、以下のようにします。
AllCops: Exclude: - db/schema.rb
ただし、このように書くと、デフォルトで設定されているExcludeが無効化されてしまいます。
そのため、デフォルトExcludeされている'vendor/**/*'
も引き続きしたい場合には、
AllCops: Exclude: - db/schema.rb - 'vendor/**/*'
というように記載しないと'vendor/**/*'
が除外対象になりません。
参考: rubocop gemを使うためにたった1つの重要なこと
Copの無効化/有効化(Enabled: false/true
)
あるCopが、プロジェクトにそぐわないと考えられる場合、個別に無効化することが出来ます。
例えばStyle/StringLiterals
というCopがあります。
これは「変数展開が不要なStringのリテラルについては、常にシングルクオートを利用する」というルールです。
これを無効化する場合、以下のように、Copの名前に続けてEnabled: false
とします。
Style/TrailingComma: Enabled: false
オプションのあるCopの設定例
Copによっては、設定できるパラメータ(Configuration parameters
)が決まっているものがあります。
例えば前出のStyle/StringLiterals
というCopは、変数展開が不要なStringのリテラルについて、
常にシングルクオートを用いる(デフォルト)か、常にダブルクオートを用いるか、
という2種類の選択肢があります。
EnforcedStyle: single_quotes # デフォルト EnforcedStyle: double_quotes
デフォルトはsingle_quotes
ですが、double_quotes
のほうが好みの場合は
Style/StringLiterals: EnforcedStyle: double_quotes
というようにします。
その他の設定
その他の設定については、rubocop gemの中のconfig/default.yml(githubのソース)
にデフォルトのルールがありますので、そこを参照してください。
.rubocop_todo.yml
の使い方
もし直さなければならない違反の数がとても多い場合は、.rubocop_todo.yml
というファイルを生成し、それをTODOリストとして活用するという方法があります。
.rubocop_todo.yml
は--auto-gen-config
オプションを使って簡単に生成することが出来ます。
先ほど作成したtest.rb
という名前のファイルをもう一度以下の内容で作成します。
def badName if something test end end
つぎに--auto-gen-config
オプションをつけてrubocopを実行します。
$ rubocop --auto-gen-config test.rb
すると.rubocop_todo.yml
というファイルが生成されます。
内容は下記のようなものです。
$ cat .rubocop_todo.yml # This configuration was generated by `rubocop --auto-gen-config` # on 2015-03-09 19:07:44 +0900 using RuboCop version 0.29.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. # Offense count: 1 # Configuration parameters: SupportedStyles. Lint/EndAlignment: AlignWith: variable # Offense count: 1 # Configuration parameters: MinBodyLength. Style/GuardClause: Enabled: false ....
このymlファイルは、.rubocop.yml
と同じ様式のymlファイルであり、
現状のコードが違反したCopをそれぞれ無効化する設定を出力します。
こうして生成されたファイルを.rubocop.yml
側から呼び出します。
inherit_from: .rubocop_todo.yml
これにより
- 「守るべきルール」である
.rubocop.yml
と
- 「今後直すべき違反」である
.rubocop_todo.yml
とを明示的に分けることができます。
違反を直す作業にとりかかる際は、.rubocop_todo.yml
にある項目を1つずつ消しながら修正する、というようにすれば良いでしょう。
-a(--auto-correct)
オプション
一部の違反については、-a
オプションをつけてrubocopを実行することで、コードが自動的に修正することができます。
--auto-gen-config
オプションを使って生成された.rubocop_todo.yml
の中に、auto-correct可能なものはCop supports --auto-correct
と書かれています。
ただし、この機能は実験的な機能とのことなので、注意が必要です。
.rubocop.yml
の例
オープンソースで公開されている.rubocop.yml
の例を挙げます。
-
BBC-News/rubocop-config
- https://github.com/BBC-News/rubocop-config/blob/master/.rubocop.yml
- 英国国営放送BBCがGitHubにアップしている設定ファイルです。
-
thoughtbot/hound
- https://github.com/thoughtbot/hound/blob/master/config/style_guides/ruby.yml
- thoughtbot社が運営する自動レビューサービス「hound」のRailsアプリにコミットされている設定ファイルです。
- thoughtbot社はスタイルガイドも公開しており、これと比較するのも面白いかもしれません。
-
spree/spree
- https://github.com/spree/spree/blob/master/.rubocop.yml
- spreeは、オープンソースのECサイト用Railsアプリです。
最後に
RuboCopはSideCI上でもご利用頂けます。GitHub上でPull RequestをOpen, もしくは更新した際に、RuboCopがSideCI上で自動的に実行され、Pull Request上に指摘内容がコメントされます。
.rubocop.yml
でのカスタマイズを行わない場合には、基本的にはRuboCop標準の設定で解析は行われます。また、プロジェクトがRailsの場合には、RailsかどうかをSideCI側で自動判定し、RuboCopをRails向けの-R
オプションにて実行します。
ぜひSideCIをご試用下さい。