rubocopでrubyコードのベストプラクティスを学ぶ(Rails + Visual Studio Code)

以下の文章はこんな方を想定しています

vscodeでrailsを書いている。 自分のコードをもっと「いいコード」にしたい。が、指導してくれる人間は周囲にいない。

rubocop

github.com

rubyコードの静的解析を行うGem. ベストプラクティスに従っていない箇所を指摘してくれる。 ベストプラクティスについてはデフォルトで設定されている。変更もできる。

インストール

公式のインストール方法は以下のとおり。

github.com

自分はbundlerを使いインストールした。

group :development, :test do
+  # コードの静的解析ツール
+  gem 'rubocop', require: false
end
bundle install

以下で解析が走る。

rubocop

いい感じの解析ルールを設定する

ネットを見る感じ、デフォルトのルールはそのまま使っているひとはあまりいなさそう。厳しすぎるらしい。

しかし、自分で設定する気は起きない… @onk さんの設定を真似させていただくことにした。

github.com

group :development, :test do
   # コードの静的解析ツール
   gem 'rubocop', require: false
+  # rubocopの解析ルール設定
+  gem 'onkcop', require: false
 end
bundle install
bundle exec onkcop init

自動生成されたファイルを編集する

 inherit_gem:
   onkcop:
     - "config/rubocop.yml"
     # uncomment if use rails cops
-    # - "config/rails.yml"
+    - "config/rails.yml"
     # uncomment if use rspec cops
-    # - "config/rspec.yml"
+    - "config/rspec.yml"

 AllCops:
   TargetRubyVersion: 2.5
   # uncomment if use rails cops
-  # TargetRailsVersion: 5.1
+  TargetRailsVersion: 5.1
rubocop

で走る。解析ルールがrubocopデフォルトから変更されていることを確認する。自分の場合、

- 59 files inspected, 284 offenses detected
+ 58 files inspected, 216 offenses detected

と変化した。(このあたり、間にほかの操作を入れたかもしれません。とりあえず、vimとかでシングルクオートで文字列リテラルを宣言したときに、『[Style/StringLiterals] Style/StringLiterals: Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.』と怒られるようになっていれば、onkcopのルールが適用されているはずです。)

プロジェクトで動かしてみる

とりあえず試す

bundle exec rubocop で解析結果が出力される。自分の場合、たしか数百件のアラートが出た。アラートが大量に出るので面食らうが、ほとんどは自動修正できるものか、メトリクス関連(メソッドが長すぎる、など)だった。手動ですぐに直すべき箇所は少ないので、ビビらないでいいと思う。

自動修正する

bundle exec rubocop --auto-correct で、自動修正できるものはしてくれる。自分の場合、アラートは半分以下に減った。修正のほとんどは空白文字関連。自分が面白いと思ったのは以下の自動修正。

&:symbolによる圧縮
users.map{|user| user.id}
=>
users.map(&:id)
if文(というか返り値があるので式)の返り値を使って代入
if condition
  @user = foo
else
  @user = bar
end
=>
@user = if condition
          foo
        else
          bar
        end
ミュータブルな定数のフリーズ
SOME_CONSTS = %w[aaa bbb ccc]
=>
SOME_CONSTS = %w[aaa bbb ccc].freeze

(注: rubyの定数は再代入が可能)

【2018/02/20追記 Pocke様からご指摘をいただき修正】

freezeすることで、オブジェクトの変更ができなくなります。 (フリーズしても、定数への再代入は引き続き可能です。)

以下、freezeについて調べたメモ。

# 配列をフリーズ
NAMES = %w[yamada sato].freeze
=> ["yamada", "sato"]

# 配列への変更はできない
NAMES.sort!
#=> FrozenError (can't modify frozen Array)

# 配列をfreezeしても、配列の要素の変更はできる
NAMES.map!(&:upcase)
#=> FrozenError (can't modify frozen Array)
NAMES.map(&:upcase!)
=> ["YAMADA", "SATO"]
NAMES
=> ["YAMADA", "SATO"]

# 中身もフリーズすれば、上の操作も防げる
OTHER_NAMES = %w[takahasi akiyama].map(&:freeze).freeze
=> ["takahasi", "akiyama"]
OTHER_NAMES.map!(&:upcase)
FrozenError (can't modify frozen Array)
OTHER_NAMES.map(&:upcase!)
FrozenError (can't modify frozen String)

# freezeしても再代入はできる
OTHER_NAMES = ["bukkowasu"]
(irb):12: warning: already initialized constant OTHER_NAMES
(irb):8: warning: previous definition of OTHER_NAMES was here
=> ["bukkowasu"]
OTHER_NAMES
=> ["bukkowasu"]

【2018/02/20追記 Pocke様からご指摘をいただき修正 おわり】

残りを適宜手動で直す

bundle exec --auto-gen で、解析結果のまとめが.rubocop_todo.ymlに出力される。内容を見て、すぐ直せるものは修正していく。 メトリクス系(メソッドが長すぎる、等)はおいおい修正したい。

vscodeの設定

vscodeでもrubocop && onkcopが効くように設定する。

プラグインをインストール

以下の公式の記述に従い、Rubyプラグインをインストールする。

marketplace.visualstudio.com

設定ファイルを作成

vscodeの設定にはスコープがふたつある。ユーザーとワークスペースだ。 たとえばプロジェクトごとに設定を分けたい場合は、ワークスペース設定を行う。 わけなくていい場合はユーザー設定を行う。

以下に従い、ワークスペース設定を開く。

code.visualstudio.com

ruby language settingsを見つける。「設定の検索」欄に『ruby』と入れるとかんたんに絞りこめる。

ワークスペースを適宜設定する。設定は以下に記載がある。

marketplace.visualstudio.com

自分は以下のようにした。

{
    "ruby.lint": {
        "rubocop": true
    }
}

code.visualstudio.com

vscodeを再起動してrubyファイルを開くと、規約に従っていない箇所に緑の波線が入る。たしかにrubocopのチェックが走ることを確認した。指摘のでないかたは、完璧に従っているコードを書いている懸念があるので、おかしなコードをかいてみてください:)

自分はシステムには入れず、プロジェクトのvendor/bundle以下にrubocopを入れているが、特にそれを明示せずともうまく動いた。