RuboCop on RBS

rubocopをRBSファイルにも効かせたい - スペクトラム で作ってたものが大体できてきて、rbs v3.5もリリースされたので公開できるようになりました。

これでRuboCopをRBSファイルにも使用できるようになりました。

github.com

例えば

class Foo
def foo: () -> void
end

というRBSをレビューする時「インデント入れてね」と指摘したくなりますよね。Rubyファイルならrubocopでできるのに、RBSファイルではrubocopで指摘できないという問題がありました。あるんです。きっと。というわけで、できるようにしました。

とりあえず初期バージョンでは20以上のルールを用意しています。

autocorrect(自動修正)にも対応しているので、いつものようにrubocop -aしてあげれば

class Foo
  def foo: () -> void
end

とrubocopが修正してくれます。

CLIで実行するもよし、CIに設定するもよし、エディタ上でLSPとして使用するもよしと、RBSの記述へのハードルが下がることを目指しています。

RuboCop on RBS

ちょけたネーミングですがワケがあります。rubocop-rbsの名前は使えなかったのです。それだけです。

rubocop-de-rbsとちょっと迷いました。

つかいかた

使い方は、rubocop-rails等ふつうのrubocop拡張と同じです。.rubocop.ymlのrequireに追加するのがオススメです。

Departments

20以上の機能があり、.rubocop.ymlで設定を切り替えられます。 機能追加のリクエスト待っています。

RBS/Layout/*

インデントやスペースの指摘、およびautocorrectによる自動修正ができます。 rbsリポジトリに記載されているスペースやインデントを正しいものとしています。

全てのトークン間で多すぎるスペースを指摘することもできます。 このためにRBSにトークン別にパースする機能を入れてもらいました。 Implement token list API by ksss · Pull Request #1829 · ruby/rbs · GitHub

  • コメントのインデントがずれてると指摘
  • overload間の空改行があると指摘
  • class/module/interfaceとendのインデントが合ってないと指摘
  • スペースが無駄に多すぎると指摘
  • class/module/interfaceがあるたびにインデントをスペース2つ分深くなってないと指摘
  • overloadの:と|の縦が揃ってないと指摘
  • ->の前後は1スペースじゃないと指摘
  • ブロックを表す{}の前後は1スペースじゃないと指摘
  • def foo:の:の前はスペースをなくすよう指摘
  • :ã‚„|のあとは1スペースになるよう指摘
  • 行末の余分なスペースを指摘

RBS/Lint/*

RBSのシンタックスエラーや、rbs validateでワーニングやエラーになる構文を指摘してくれます。

  • シンタックスエラー
  • 型引数を全く使っていないと警告
  • Array等、型引数を指定しなければいけない型なのに、型引数がついていなかったり多かったりしたら警告
  • メソッド引数にvoidを使用したら警告

rbs validateを実行しなくてもRuboCopで指摘してくれるのですぐに問題に気づけます。

若干SteepのLSP機能と被っている場合もありますが、RuboCop on RBSでは軽量に分かるものを、Steepでは名前解決が必要な重いものを見れればいいのかなと思っています。

RBS/Style/*

この書き方より、こっちの方がいいですよ系。 主に型の書き方で無意味な重複があったりすると教えてくれます。 自動修正にも対応しているので便利。

  • ブロックの返り値にboolを使っている時は指摘
  • TrueClass, FalseClass, NilClassを使っていると指摘
  • Integer | Integerのような重複があると指摘
  • initializeの返り値はvoidでないと指摘
  • untyped | Stringは結局untypedなので指摘
  • nil?のような重複した定義を指摘
  • true | falseを使用した場合、boolに直すよう指摘

どうやってやってるの?

rubocopは、Rubyとしてパースし、シンタックスエラーが発生したらon_other_fileを呼び出しますという挙動になっています。

このon_other_fileでRBSとしてパースして、さまざまなCopに利用しています。RBS::Parser.parse_signatureでパースしたASTには位置情報も含まれているのでこれを利用しています。

また、RBS::Parser.lexというAPIも増えたので、これで全てのトークンの位置情報を細かく取得できます。これもガッツリ使っています。なのでrubocop-on-rbsはrbs v3.5から使うことができます。

VSCode対応

VSCode対応もできています。

ですが https://github.com/rubocop/vscode-rubocop/pull/28 で提案中なので自分でextensionをbuildするか、~/.vscode/extensions/を直接書きかえる必要があります。(方法はrubocop-on-rbsのREADME.mdに書きました。)

エディタでリアルタイムフィードバックがあると次元の違う開発体験ができるので、ぜひ実現させたい機能です。

将来的に

ruby/rbsやruby/gem_rbs_collectionに導入して、PRがきたらCIで機械的に指摘できたらいいなと思っています。

もちろんあなたのリポジトリにも使っていただけると大変嬉しいです。