LoginSignup
20
2

More than 1 year has passed since last update.

IRBの補完にRBSを組み合わせてみる

Last updated at Posted at 2022-12-19

カタカタッ ターンッ! RubyのIRBめっちゃ便利ですよね。
IRBは補完機能もすごく便利なんですが、ちょっと気になるところもあります。

  • メソッドチェーンすると正しく補完できずありとあらゆるメソッド名が候補に出てしまう
  • 正規表現で実装されてるので時々誤作動を起こす
    • array[i]. %s[symbol]. 配列のメソッドが候補に出る
    • array.map{}. %w{words}. HashとProcのメソッドが候補に出る

なので、型情報(RBS)とかも使ってもうちょっといい補完候補を出せないかなと 、gem katakata_irb を試しに作っています。

gemをインストールするとkirbコマンドが使えるようになります。
変えました。使い方: require 'katakata_irb'

メソッドチェーンしてても、ブロック引数・変数などを使ってても、ある程度正しく型を推測して補完候補を出せたり出せなかったりします。

katakata0.png

katakata1.png

katakata2.png

実装

こういうコードをirbに入力したときに

irb> a = 10
=> 10
irb> a.times.map do |i|
irb>   j = i.times.map{}.join
irb>   j = a if foobar
irb>   puts((j * 2).
irb>   ...
irb>   ...
  1. カーソルより前の文字列を抜き出す
  2. rubyのコードとして不完全なので、足りていない)endなどを追加したSyntax Validなコードから構文木を作る
    sexp = Ripper.sexp(code + "method\n)\nend")
  3. 補完したい位置に該当する構文木のノード((j * 2).method)を探す
  4. ローカル変数aの中身やrbsの型情報を使って(j * 2)が何になり得るかを調べ、この場合はIntegerかStringなのでIntegerとStringのメソッドを補完候補に出す

ということをしています。

※ 不完全なコードのparseには、Ruby3.2から入るRubyVM::AbstractSyntaxTree.parseのerror_tolerantオプションが使えるかもしれない

未実装な部分

  • Tuple, Record, Interface型などに対応していない
  • unless a.is_a? Foo で aからFooが除外されてほしい
  • TODOコメントを残した箇所がたくさんある
  • 直前の解析結果を使いまわせる場合があるのでキャッシュしたい

動機

  1. irbのruby-lex.rbを読んでいたら自分で書き直したバージョンを作ってみたくなった
  2. 書き直した結果、閉じられていない括弧・do・quoteなどを調べるメソッドができた
  3. それを使えば正規表現ではなく構文木から補完候補を出せそう
  4. 型情報も使うとメソッドチェーンの補完候補も正しく出せそう
  5. ブロック引数の型も調べたい、型推論っぽいことをしよう
  6. 気軽に手を出した型推論、めちゃくちゃ大変じゃん(←今ここ)

その他

僕が快適に使いたいからという理由でirb/ruby-lex.rbとrelineにいくつかパッチを当てて読み込んでます。
(Module#remover_method Module#prepend RubyVM::InstructionSequence.load_iseqなどを使って)
ヒアドキュメントのインデントとかが良い感じになってるはず。うまくいけばirbにリファクタリングのプルリクを出したい。
パッチあてるのやめました

Merry Christmas

Ruby3.2楽しみ

20
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
2