社のRailsアプリにrubocop-rubycwを導入していた。
これは大変便利なRuboCopプラグインで、ruby -cw ...によって出力される警告を、あたかもRuboCopの警告であるかのように扱うことができる。普段あまり意識されないがちなRubyインタプリタの警告を、みなさんが使っているRuboCopにのせることで使ってもらいやすくするのが目的。
警告が全部出る状態でRSpecを走らせて警告を修正していたのが始まり。警告を修正するPRで合わせてこのgemの導入もした。
このgemの導入に合わせて、社内の有識者に「RubyVM::AbstractSyntaxTreeがdeprecateされるけど大丈夫そ?」(意訳)という意見をもらった。このgemではRubyVM::AbstractSyntaxTreeを警告の検出に使っている。ruby -cwe CODEのようにコマンドを実行することでも警告は検出できるけど、それではあまりにも遅いので、同じプロセス内でパースをすることで検出をしている。
雑に試した感じだと、Prismを使うとwarningsメソッドで警告を取得できるので、置き換えが出来そうに見える。
$ ruby -rprism -e 'pp Prism.parse("1").warnings'
[#<Prism::ParseWarning @type=:void_statement @message="possibly useless use of a literal in void context" @location=#<Prism::Location @start_offset=0 @length=1 start_line=1> @level=:verbose>]
ただしこれには罠があり、正規表現内に関してはPrismは警告をしてくれない。
ということで、Prismに置き換えるなら正規表現の問題を見なかったことにするか、Prismが返すASTから正規表現リテラルを抜き出してRegexp.newに渡すかしかなさそう。もしくはいっそRuboCopの1つのCopとして実装してしまうか。
# RubyVM::AST ならば警告が出る
$ ruby -we 'RubyVM::AbstractSyntaxTree.parse("_=/[aa]/")'
(none):1: warning: character class has duplicated range: /[aa]/
# Prism では警告が出ない
$ ruby -rprism -we 'pp Prism.parse("_=/[aa]/").warnings'
[]
なお、ruby -cwe ...を使った場合もPrismだと正規表現の警告は出ないようになっていた。
$ ruby --parser=parse.y -cwe '_= /[aa]/' -e:1: warning: character class has duplicated range: /[aa]/ Syntax OK $ ruby -cwe '_= /[aa]/' Syntax OK