コンテキスト
僕が直近2〜3年以内に新しく作ったgemでは全てrbsとsteepを導入してガッツリ型を書いています。
しかし自分のgemのrbsは書けても、自分のgemが依存しているrubyの標準ライブラリのメソッドや依存している別のgemの方で型定義がなかったり足りていなかったりして steep check
が通らなくて困ることがよくあります。
こういう時には https://github.com/ruby/gem_rbs_collection や https://github.com/ruby/rbs にパッチを送ればいいんですが、とはいえ本家に取り込まれるまで自分のgemの開発が止まるのはつらいのでfork版を使うことが多いでしょう。
しかし足りない型定義が多かった時にfork版をメンテするのもつらい気がしているので*1僕はモンキーパッチとしてrbsを入れるようにしています。
こういうことは多分自分しかやっていないだろうなあと思いつつ、他の人がどうやってるか知りたいので自分が普段やってることを紹介してみます。
構成
下記のように sig/non-gemify/
のようなディレクトリを作って、ここにモンキーパッチrbsを入れています。
$ tree sig/ sig/ ├── non-gemify │ ├── io.rbs │ └── kernel.rbs ├── ruby_header_parser │ ├── argument_definition.rbs │ ├── config.rbs │ ├── enum_definition.rbs │ ├── function_definition.rbs │ ├── parser.rbs │ ├── struct_definition.rbs │ ├── type_definition.rbs │ ├── typeref_definition.rbs │ └── util.rbs └── ruby_header_parser.rbs 3 directories, 12 files
sig-non-gemify/
のようにしてもよさそうですが好みの問題かと思います。
エディタやIDEによっては sig/
以外のディレクトリを認識しなくて困ることをなんとなくエスパーして sig/
の中にサブディレクトリを作る方法にしました。(杞憂かも)
手順
モンキーパッチrbsをgemファイルに含めて https://rubygems.org/ で配布を行うと、そのgemをインストールしたユーザの開発環境に悪影響が起きるかもしれません。
そのため、gemspecで下記のように除外設定を入れた方がいいです。
spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls| ls.readlines("\x0", chomp: true).reject do |f| (f == gemspec) || - f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile]) + f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile sig/non-gemify]) end end
あとはsig-non-gemify/
のように sig/
ディレクトリの外に置くようにした場合には下記のように Steepfile
に設定追加も必要だと思います。
target :lib do
signature "sig"
+ signature "sig-non-gemify"
モンキーパッチrbsが完全になくなった時に Steepfile
に存在しないディレクトリを書いた時にエラーにならないかも気になったんですが、今のsteepの最新版(1.8.3)だと問題なかったです。
モンキーパッチrbsを使うメリット
- 本家のgem_rbs_collectionを併用できるので常に最新を使い続けることができる
- 本家に投げたパッチが取り込まれた時に自分のgemではそのモンキーパッチrbsだけを消すだけでいい
- 一気に取り込まれるとは限らないのでマージされたものから段階的にモンキーパッチrbsを消すことができる
僕が以前rbsに出したパッチが取り込まれてリリースされてた。これで自分のgemに入れてるモンキーパッチrbsがまた1つ消せるようになったhttps://t.co/KdHMjQDXKyhttps://t.co/VFfCMg90gO
— sue445 (@sue445) 2024年12月5日
最後に
みんなのgem開発時のこの手の困りごとの解決方法を知りたいので教えてください!!!
2024/12/05 20:27追記
ruby-jp slackで聞いたら
sig/gems/ ってディレクトリにいろいろ放り込んでますね。取り込まれた後にお掃除してます、
とのことだった。そうなりますよね...
*1:実際にそういう運用はしたことないのであくまで想像