ruby 3.4リリース
Ruby 3.4が出て2月ほどが経ちましたね。 私は去年のRuby 3.3リリースに合わせたRBSの記事を書かせていただきました。
新機能ラッシュ! RBS最新情報をキャッチアップ | gihyo.jp
今年はこの企画自体がなかったので個人のブログで簡単に書いておくことにします。
RBS::UnitTest
の追加
RBS記述が実際のRuby許動に沿ったものなのかテストするためのフレームワークが提供されるようになりました。 これまでrbsリポジトリー内でだけ使われていたものを、gemなどでも利用できるようになっています。
def test_foo assert_send_type( "(Integer) -> String", YourGemClass.new, :foo, 123 ) end
サンプルコードを読み解くと、YourGemClass
というclassのインスタンスメソッドfoo
に123
という引数を与えて動かすと、(Integer) -> String
、つまり引数にはInteger、返り値にはStringが返ることを期待するテストコードになります。
さらに裏では記述されたRBSもチェックしています。RBSの記述、実装者の期待値、実際のRubyの挙動の3点から整合性を確認できます。
Recordタイプにオプショナルなキーを指定できるように
Recordタイプ(e.g. { foo: Integer }
。固定のHash的なやつ)で、あってもなくてもどっちでもいいけどもしもあったら型チェックしてほしい。。。そんな指定ができるようになりました。
# aaa({ foo: 123 }) => OK # aaa({ foo: 123, bar: 'zzz' }) => OK # aaa({ foo: 123, bar: 234 }) => Error # aaa({ foo: 123, zzz: 'zzz' }) => Error def aaa: ({ foo: Integer, # これまで通りの必須キー ?bar: String # 必須ではないオプショナルキー }) -> void
引数が全くわからない場合のメソッド記述が可能に
メソッドに対して、引数が全くないのか、なんでも受け付けるのか、まったく分からないことを表すことができるようになりました。移譲などで引数の数や形式が変わる場合に便利です。
# 従来のあらゆる引数を受け入れる記述 # これでは引数がまったくないことを表せない def foo: (*untyped, **untyped) -> void # `(?)`と書くと「引数まったくわからんから何でもおk」を表現できる def foo: (?) -> String # Procやブロックでも`(?)`が使える def bar: (^(?) -> void) { (?) -> void } -> void
RBSのトークン列が取得できるように
RBS::Parser.lex(source)
RBSライブラリーのRuby APIとして抽象構文木(AST)を構築する前のトークン列を取得できるようになりました。 このAPIはrubocop-on-rbsを開発していて欲しくなった機能で、抽象構文木では取りにくいトークンの位置情報を取得して問題を報告させるのに役立てています。APIはPrismを参考にしました。
def foo: (aaa: Integer) -> void ^ スペースが2つ続いていることを指摘したい
Genericsの強化
型引数の制約条件が緩くなりました。あんまり使うことない?
interface _Foo[T < String?] def foo: () -> T end type foo = _Foo[String] # OK type bar = _Foo[Integer?] # Error
また、型引数にデフォルトの型を指定できるようになりました。型引数は一度つけば毎回指定しなければいけなくなるのが面倒ですが、これで使いやすくなりそうです。
# `_Each[Integer]`だけで使えるようになる interface _Each[Element, Return = void] def each: { (Element) -> void } -> Return end
bundled gemが徐々にrbsリポジトリーを卒業していくことに
bundled gemはRuby本体でのメンテナンスを離れてgemとして独立していったgem達です。つまり普通のgemにかなり近い存在です。これをrbsリポジトリーで持つのはもう違うよねーということで、rbsリポジトリーからbundled gemをなくしていくことになっています。ユーザー的にはあんまり意識することはないかもしれません。PR送る先で困るかも。。。わかりやすく整理します。
もしmanifest.yaml
を書いている上級者の方々は、ここにbundled gemを書かないようにしていってくれると助かります。
Kernel#Namespace
と Kernel#TypeName
がdeprecatedに
RBSに関心がなくても遭遇する可能性があります。
Namespace()
というメソッドとTypeName()
というメソッドがあるのですが、今後RubyでNamespace機能が搭載される予定ですしややこしいということでdeprecatedになり、使用しているコードで警告が出るようになりました。
もし警告を見たらライブラリーをアップデートするか、警告を出している(TypeName()
を使用している)ライブラリーにPRを送ってみてください。
今後
2024年の出来事ということでここまでで終わりですが、RubyKaigi 2024でも話されたrbs-inlineに対する界隈の関心は高く、rbsリポジトリーにいつかmergeされる予定とどこかで聞いたことがあるので注目ですね。