自分で開発しているRuby用のライブラリに型情報を足す

仕事で忙殺され気味のため久々の更新。

playwright-ruby-clientにいきなり「型書け」ってissueが飛んできた。

github.com

個人的にはGitHub Copilotにどっぷり浸かっていて、「Rubyだったらべつに型いらんくね?」って考えなんだけど、playwright-ruby-clientに関してはユーザが触るコードは全部自動生成しているので、コード生成スクリプトにちょろっと追記したら手で型定義書かなくてもRBSも自動生成できるんじゃないか?と試してみた。

どういう状態にしないといけないか

RBSを"使う"側つまり、ライブラリを使ってコードを書く側の話はぐぐるとたくさんでてくるが、Gemを開発している人は何をやればいいのか?というのはそんなに情報がない。

唯一、この記事↓がまさにそれを紹介していた。

blog.kymmt.com

結論から言うと、ライブラリの開発者がやらないといけないことは至極単純で、 sig/your_library.rbs のファイルを同梱するだけ 。

.
├── CODE_OF_CONDUCT.md
├── Gemfile
├── Gemfile.lock
├── LICENSE.txt
├── README.md
├── Rakefile
├── bin
│   ├── console
│   └── setup
├── lib
│   ├── playwright
│   ├── playwright.rb
│   └── playwright_api
├── pkg
├── playwright.gemspec
├── sig ←★これを追加
│   └── playwright.rbs
└── spec

どんな型定義を書かないといけないのか

型定義はいきなり書けと言われて所見で書けるものではない。まずはTypeProfで雛形を作成する。

typeprof lib/playwright_api/*.rb -I lib/playwright -o sig/_playwright.rbs

これだけで割とそれっぽい型定義は作られる。

あとは、 sig/_playwright.rbsを参考に、 sig/playwright.rbs を頑張って作る。

さらにそれをTypeProfに食わせてみて、書いた型定義にミスが無いかを確認する。

typeprof sig/playwright.rbs lib/playwright_api/*.rb -I lib/playwright -o sig/_playwright.rbs 

rbs validateなどもあるが、typeprofだけでも結構いける。

「こんなときどう書けばいいの?」って疑問は、9割がた↓の記事をみて解決できた。pockeさん神記事です。

pocke.hatenablog.com

TypeProfの "unhandled exception" 問題

TypeProfに食わせるrbsファイルに不備があると、 "unhandled exception" っていうエラーが出て2回ハマった。

結論、以下の2つがハマりどころでした。

  • パラメータ名が "type" だとダメ
  • Arrayã‚„Hashは Array[untyped] Hash[untyped, untyped] って書かないとダメ

型を書いてみた結果...

RBSをサポートしてるぜって熱弁しているRubyMineをインストールして、対応前後の動きをみてみた。

もともとがこんな感じ。ほとんど何も補完が効かない。これならVSCodeやSublime Textで十分、ってかんじ。

対応後はこんな感じ。「コード補完ほしい」「型書け」って言う人達にとってはまぁ嬉しいんだろうなという結果。

でもGitHub Copilotはもっとすごいよ...

型を書く書かないにかかわらず、Copilotはこのレベルで補完をガンガンしてくる↓

  • どちらかというと自分のライブラリのサンプルコードを世の中にバンバン出していくほうが、Copilotによる補完精度が上がって、ユーザにとってはありがたいんでは?
  • まだ人気のないライブラリに限ってはRBS書いたほうがよさそう

という所感に落ち着く。

まとめ

Gemを自分で作ってる人は sig/your_library.rbs を足すだけで「型書け」には答えられる。

蛇足: 「型書け」と言ったからには責任を!

GitHub Copilotにどっぷりな身としては、「なんとなくコードの補完効いてほしいよね〜」くらいのレベルで「型を書け」というのはRubyにおいては正しくないと思う。

Add type signatures (RBS) · Issue #239 · YusukeIwaki/playwright-ruby-client · GitHub

この手のissueを放り投げるのは、考えるきっかけとしてはありがたかったものの、「型書け」って人に言うからにはしっかり議論やフィードバックしてくれ!ってのが本音。