Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Ruby 4.0の主要機能とリリースハイライト、アップグレードガイド

Ruby 4.0は、2025年12月25日、Ruby誕生30周年を記念してリリースされた大型バージョンアップです。破壊的な変更を伴うものではなく、30年間のコミュニティの歴史を祝う意味合いが込められています。

実はRubyはセマンティックバージョニング(semantic versioning)に厳密には従っていないことを知って驚きました。

代わりに、Rubyの生みの親であるMatz(まつもとゆきひろ氏)は、変更内容が彼を「感動させた」ときにメジャーバージョンを引き上げるのです。このバージョンはRubyの30周年を記念するとともに、言語をさらに拡張する機能を多数導入しています。

Ruby 4.0の主要機能とリリースハイライト、アップグレードガイド

Ruby 4へアップグレードするRubyistにとって朗報なのは、アップグレードが比較的スムーズに行えるという点です。Ruby::BoxZJITといった新機能、並行処理の改善などが追加されていますが、そのほとんどは後方互換性を保っています。

それでは、Ruby 4で何が変わったのか、そしてどのようにスムーズにアップグレードできるのかを見ていきましょう。

Ruby::Boxとは?

Ruby 4.0で最も注目すべき実験的機能のひとつがRuby::Boxです。これはRubyプロセス内に分離された名前空間、いわば「コンテナ」(Dockerコンテナとは別物です)を導入するものです。

本質的には、Rubyプロセスの中に隔離されたRubyの世界を作り出す仕組みです。新しいRuby::Boxを作成すると、そのBox内で読み込まれたクラス、モジュール、グローバル変数、定数、さらにはC拡張まで、すべてそのBoxの中に閉じ込められます。

言語レベルでの軽量な仮想化のようなもので、各Boxは独自の状態を持ち、他のBoxやメイン環境に定義が漏れ出すことはありません。

ただし実験的な機能のため、不安定な挙動や予期しない問題に遭遇する可能性があります。パフォーマンスオーバーヘッドも考慮が必要です。分離にはコストがかかるため、コアチームは意図的にオプトイン方式を採用しています。

Ruby 4.0の時点では、Boxは即座に真の並列実行を提供することを目的としていません。より賢いコードローディングの基盤を築くものであり、今後さらに発展していく可能性を秘めています。Rubyがこんなにも面白い方向に進化しているのを見るのはワクワクしますね。Ruby Boxを使いたい場合は、まず環境変数を有効にする必要があります:

RUBY_BOX=1

ZJITが重要な理由

Ruby 4.0では、YJITの後継として開発された全新的なJITコンパイラ「ZJIT」が導入されました。数えてみれば、MRIにはついに2つのJITコンパイラが搭載されることになります。ZJITはYJITとは異なるアプローチで、両者は並行して開発されています。すでにYJITを使っているなら、無理に切り替える必要はありません。

YJITのおさらい

YJIT("Yet Another JIT")はShopifyによって開発され、Ruby 3.1で導入されました。Lazy Basic Block Versioningという手法を採用しており、小さなコード塊(基本ブロック)をその場でコンパイルし、実行時の型情報に基づいて特殊化します。

YJITは多くのRubyアプリケーションを大幅に高速化することが証明されており、導入も比較的容易です。Rustで書かれており、近年のRubyバージョンにおけるデフォルト/主力JITとなっています。

ZJITとの違い

ZJITはより伝統的なメソッドベースのJIT戦略を採用しています。小さなブロックを少しずつコンパイルするのではなく、SSA(Static Single Assignment)中間表現と、より一般的なコンパイラパイプラインを使用して、より大きな単位(メソッド全体や大きなコードチャンク)をコンパイルします。

いわば「教科書的」なJITコンパイラとして設計されており、コントリビューターにとって理解しやすく、改善もしやすいのが特徴です。

Rubyコアチームは、ZJITに関する2つの目標を明示しています。1つはYJITでは実現できないより高度な最適化を可能にすることでRubyの長期的なパフォーマンス上限を引き上げること、もう1つはJITをコミュニティにとってハッキングしやすくすることです。

Ruby 4.0でZJITを有効にする

ZJITは利用可能ですが、Ruby 4.0ではデフォルトで無効になっています。

試してみるには、システムにRust 1.85以上がインストールされた状態でRubyをビルドする必要があります。JITのコード自体はRubyバイナリの一部ですが、ビルドにはRustが必須です。その後、'--zjit'フラグを付けてRubyを実行すればZJITを使えます。

JITをデフォルトのままにしていれば、引き続きYJIT(これ自体も改良が続けられています)の恩恵を受けられます。なお、--rjitフラグを使用していた場合は、このリリースで削除された点に注意してください。

Ruby 4のRactor改善

Ruby 3.0で導入されたRactorは、並列処理のための実験的機能です。Ractorを使うと、単一プロセス内で複数のRubyインタプリタ(コードを実行するシステム部分)を動かせるため、通常Rubyを一度に1スレッドに制限するGIL(Global Interpreter Lock)を回避できます。筆者自身はRactorを使ったことはありませんが、継続的な投資が続けられていることは、それがRubyの未来にとって重要であることの明確な証です。

Ruby 4.0でもRactorは依然として実験的マークが付いていますが、主流での使いやすさに近づけるための大幅な改善とAPI変更が加えられました。

Ractorを使ったことがある方なら、メッセージの送受信が少し扱いにくかったことをご存知でしょう。Ruby 4.0では既存のAPIが、より堅牢なRactor::Portメカニズムに置き換えられました。Ractor::Portは本質的に、Ractor同士が値をやり取りするためのパイプまたはチャネルです。各Ractorはデフォルトポート(Ractor.current.default_port)を持つようになり、カスタムPortオブジェクトを作成して受け渡すこともできます。

Ractorの変更に伴い、いくつかの破壊的変更もあります。最も顕著なのは、Ractor.yieldRactor#takeが削除されたことです。

内部実装では、Ruby 4.0のRactorはパフォーマンスと安全性向上のためにチューニングされています。Ractor間の共有状態が削減されました。共有状態が減ることで、誤って分離を壊すリスクが下がり、マルチコアシステムでのCPUキャッシュ利用率も向上します。

Ractorは以前よりスケールしやすく高速に動作するはずですが、まだスレッドやプロセスほど広く使われてはいません。

Ruby 4における*.nilの変更

Ruby 4.0では、nilをスプラットしてもnil.to_aが呼ばれなくなりました。

古いRubyバージョンでは、arr = [*nil]のようなコードを書くと、裏側でnil.to_a([]を返す)が呼ばれるため、空の配列が得られていました。これは少し魔法的で一買性のない挙動でした(なぜ*nilが空配列のように振る舞うのか?)。

Ruby 4.0では、この奇妙な挙動はなくなりました。nilに対してスプラット(*)を使ってもto_aは呼び出されず、「スプラットするものは何もない」として扱われます。この変更により、Ruby 3.4で導入された、ダブルスプラット**nilnil.to_hashを呼ばない挙動とも一買性が保たれます。

Ruby 4での行頭論理演算子

これは多くのRubyistを笑顔にする、ちょっとした構文改善です!

ブール式を前の行から続ける際に、&&||andorを行の先頭に置けるようになりました。例えば次のように書けます:

if user_signed_in?
 && user.admin?
 && feature_enabled?
 perform_admin_task
end

これは以下と同じです:

if user_signed_in? &&
 user.admin? &&
 feature_enabled?
 perform_admin_task
end

これまで同じにならなかったのが不思議なくらいなので、このアップデートは嬉しい限りです。

Ruby 4のクラス関連アップデート

Ruby 4.0には、コアクラスへの細かな変更や改善も含まれています。

まず、Setクラスが組み込みコアクラスになり、require 'set'なしで使えるようになりました。これに伴いset/sorted_set.rbは削除されています。

同様に、Pathnameもコアクラスに昇格しました。

また、新しいArrayメソッドも登場しました!このリリースではArray#findのパフォーマンスが向上し、単純な線形探索よりも賢く配列を検索します。さらにArray#rfindも導入されました——タイポではありませんよ!このメソッドは配列内で条件に一致する最後の要素を見つけます。

Ruby 4では、新しい数学メソッド、イントロスペクション制御、Enumeratorの改善なども追加されています!改善の完全なリストについては、ぜひ公式ドキュメントを確認してください。

Ruby 4へのアップグレード方法

本番アプリのRubyバージョンのアップグレードは常に慎重に行うべきですが、Ruby 3.4からの移行であれば、これまでで最も簡単なアップグレードの一つになるはずです。

安全に移行するためのヒントをいくつか紹介します:

リリースノートを読む

まず、公式リリースノートを読みましょう!公式の非推奨(deprecation)通知がないか再確認してください。ここでサプライズはないはずです。Ruby 3.4が今後の非推奨事項について警告してくれているはずだからです。

非推奨警告への対応

Rubyインタプリタからの非推奨警告を無視していた場合は、言語のアップデート前に必ず対処しておきましょう。

ベースラインテスト

次に、しっかりしたテストがあることを確認してください。これにより、アプリの挙動が変わっていないという確信が得られます。テストが一切ない場合は、少なくともクリティカルなパスをカバーするテストに投資する絶好のタイミングです。

Bundlerの更新

次にBundlerを更新しておくと良いでしょう。最新版にしたら、bundle installを実行し、エラーや警告がないか確認します。

Rubyバージョンの更新

これで新しいRubyバージョンをインストールして切り替えられます。rbenvasdfのようなRubyバージョンマネージャーは、ローカルのバージョン管理に人気があります。アプリがDockerで動いているなら、Dockerfile内のRubyバージョンを更新しましょう。Dockerなしのプラットフォームで動いているなら、そちらでRubyバージョンを更新してください。

GemfileでRuby 4.0にアップグレード

Gemfile内のRubyバージョンを更新し(rubyディレクティブで固定している場合)、最後にもう一度bundle installを実行します。

テストの実行

最後に、テストを実行しましょう!問題がなければ、アプリケーションの重要なパスを実際に一通り操作して、さらなる確信を得てください。アップグレードをリリースする前に、Honeybadgerのような例外監視サービスの利用を検討しましょう。そうすれば、Ruby 4へのアップグレードがユーザーに問題を引き起こしているかどうかを実際に把握できます。

これらの手順に従えば、Rubyの最高の機能を追いかけるのは比較的苦痛のない体験になるはずです。テストを実行するときは、Rubyの30歳の誕生日をお祝いするのをお忘れなく!


  1. Magic DashboardsでRubyアプリのパフォーマンス監視を強化する方法

    アプリケーションチームにとって、顧客がどのような体験をしているのかを把握することは不可欠です。これは、ユーザビリティやレスポンスの良さといった全般的な観点だけでなく、日々の運用における一分一秒単位の変化についても当てはまります。 特に分散システムを扱う場合、エラーの発生は避けられません。サイトへのトラフィックは一日の中で変動し、システムが依存するコンポーネントのいずれにも、いつ問題が起きてもおかしくないからです。 本記事では、「マジックダッシュボード(Magic Dashboards)」を活用して、Ruby on Railsアプリケーションのパフォーマンス問題を監視・解決する方法を解説します。

  2. FlipperのフィーチャーフラグでRailsに新機能を安全にデプロイする方法

    こんなシナリオを想像してみてください。あなたはRails開発者で、ここ数日かけて全員が待ち望んでいる素晴らしい機能を開発していました。規模は大きく複雑でしたが、厳密なテストを経ているので、すべてが期待どおりに動作すると確信しています。納期もあるため、そのままデプロイ。すると、瞬く間に大混乱に陥ります。 新機能が原因で、一部のユーザーに対してアプリ全体が動かなくなってしまったのです。理由もよく分かりません。テスト中にはバグは一切出ていなかったのに。変更をロールバックしても、被害はすでに出ています。顧客は不満を抱き、あなたは当面の間、ダメージコントロールと原因調査に追われることになるでしょう。 問