TL;DR
ruby -cw
をRuboCopのインターフェイスで扱うためのgem
ruby -cw
とは
-c
を付けると、Rubyはコードを実行せず、構文のチェックのみを行う。
-c check syntax only
-w
を付けると、Rubyは見つけた警告をすべて報告するようになる。
-w turn warnings on for your script
なお、ruby -cw
ではパース時のエラーしか発見できず、実行時のエラーは当然ながら発見されない。
# test.rb File.exists?('foo')
ruby -w test.rb のように実行すると、上のコードは次の警告を出力する。
File.exists? is a deprecated name, use File.exist? instead
ところがruby -cw test.rb
と実行しても"Syntax OK"としか表示されない。これは「File
モジュールのexists?
メソッドが呼び出されたかどうか」は実際に実行してみないとわからないからである。
一方、次のコードはruby-cw
でもruby -c
でも同じように警告を出力する。
# test2.rb a = 1 puts b
assigned but unused variable - a
これはローカル変数が使われたかどうかはコードをパースするだけで分かるからである。
rubocop-rubycwとは
rubocop-rubycwでは、その名の通りruby -cw
を実行した時に出る警告をRuboCopのoffenseとして報告するRuboCop pluginである。
前の例のFIle.exists?
はこのpluginを使っても発見できないが、ローカル変数の未使用警告であれば発見できる。
使い方
普通のRuboCop pluginと同様に扱える。
まず、Gemfile
にこのgemを追加する。
# Gemfile gem 'rubocop' gem 'rubocop-rubycw' # これを追加
そして、.rubocop.yml
に次を追加する。
require: - rubocop-rubycw
これで後は通常通りrubocop
コマンドを実行するだけである。
なお注意として、Ruby 2.6よりも古いRubyを使っている場合、Ruby 2.6以上を使っている場合に比べて実行が10倍ほど遅くなってしまう。 これは後述の実装の違いに寄るものである。
実装
前述した通り、Ruby 2.6とそれ以前で実装が異なる。
まず、Ruby 2.6以前の実装を紹介する。Ruby 2.6以前では単にruby
を外部コマンドとして呼び出して、その標準エラー出力をパースして警告をoffenseに詰め直している。これは当然遅い。1
また、Rubyコマンドのパスの取得にはRbConfigを使用している。
そしてRuby 2.6からは同バージョンで追加されたRubyVM::AbstractSyntaxTree
を使っている。
RubyVM::AbstractSyntaxTree
を使うと同じRubyプロセスの中でRubyコードをパースし、ruby -cw
と同様(たぶん)の警告を標準エラー出力に出力する。
ただし標準エラー出力に警告が出力されると扱いづらいので、Ruby 2.4から追加された Warning
モジュールを使って、発生した警告を管理するようにしている。
なお、このどちらの実装でも.rubocop.yml
で指定されたTargetRubyVersion
は無視され、RuboCopを実行しているのと同じRubyのバージョンが使われる。
このgemの実装のメインは次の2ファイルにあるので、より詳しく知りたい場合はこのあたりを読むと良い。
- https://github.com/rubocop-hq/rubocop-rubycw/blob/6527c57a27c6cefa3d8ca9cc60327620e508adb3/lib/rubocop/cop/rubycw/rubycw.rb
- https://github.com/rubocop-hq/rubocop-rubycw/blob/6527c57a27c6cefa3d8ca9cc60327620e508adb3/lib/rubocop/rubycw/warning_capturer.rb
どう使ってほしいか
これを使ってRubyの警告を減らしていってほしいと思っている。 RuboCopを有効にしているプロジェクトでもRubyの警告は野放しになっているケースはあると思っていて、このRuboCopプラグインはそのようなプロジェクトに最小限の手間でRubyの警告を監視する仕組みを入れることができると思っている。
Rubyが出す警告は(通常の)RuboCopが出す警告と違ってなるべく直して欲しいものなので、このプラグインはほとんどのRubyのプロジェクトに対して意味のあるものだと思っている。
ただし、ruby -cw
は実行時の警告を出力しないため、このプラグインだけでRubyの警告をすべて潰せるわけではないことには注意が必要である。
また、先に述べたパフォーマンス上の問題点もあり、Ruby 2.6以前のRubyを使っている環境では採用がむずかしいかもしれない。 なお、JRubyなどで動作するかは未確認である。
rubocop-rubycw の紹介をした。ぜひ使ってほしい。
合わせて読みたい
-
実は
ruby -cwe
として実行しているので、一部の警告(nanika if /re/
とか)の結果が変わってしまいそうな気がしている。直したほうが良さそう。↩