Ruby 4.0.0 リリース

Posted by naruse on 25 Dec 2025

Ruby 4.0.0 が公開されました。 Ruby 4.0 には “Ruby Box”、”ZJIT” ほか多数の改善が含まれています。

Ruby Box

Ruby Boxはクラス等の定義の分離/隔離のための機能を提供する、実験的機能です。Ruby Boxは環境変数として RUBY_BOX=1 を指定することで有効化できます。クラス名は Ruby::Box です。

Boxの中で読み込まれた定義はそのBox内に閉じた状態となります。Ruby Boxが隔離できる定義としては、既存クラスへのモンキーパッチ、グローバル変数やクラス変数の操作、クラスやモジュールの定義、そして.rbファイルや拡張ライブラリとして実装されたライブラリ類です。

Ruby Boxの主要なユースケースとしては、次のものが想定されています:

  • テストのために何かの挙動を上書きするようなモンキーパッチを必要とするテストケースをBox内に閉じて実行すること
  • WebアプリケーションをBox内で実行することで、Blue-Greenデプロイメントをプロセス内で、アプリケーションサーバ上で実行すること
  • WebアプリケーションをBox内で実行することで、依存関係の更新時などに、一定期間並列で動かしてRubyコードを用いてレスポンス等を検証すること
  • (未設計の)「パッケージAPI」のような新しい高レベルAPIを作るための低レベルAPIとしての機能を提供すること

“Ruby Box”の詳細については次のドキュメントを参照してください: Ruby::Box. [Feature #21311] [Misc #21385]

ZJIT

ZJIT は、YJIT の次世代として開発された新しい just-in-time(JIT)コンパイラです。ZJIT サポート付きで Ruby をビルドするには Rust 1.85.0 以降が必要で、–zjit を指定すると ZJIT が有効になります。

私たちが Ruby 向けに新しいコンパイラを開発しているのは、パフォーマンスの上限を引き上げ(より大きなコンパイル単位サイズと SSA IR を導入)つつ、より一般的なデザインであるメソッドコンパイラにすることで、外部からの貢献を促進したいからです。詳しくは ブログ記事 をご覧ください。

ZJITは通常の Ruby インタプリタより高速ですが、まだ YJIT ほど速くはありません。ZJIT をぜひ試してみて欲しいですが、現時点では本番環境へのデプロイは控えたほうがよいかもしれません。Ruby 4.1 の ZJIT にご期待ください。

Ractor の改善

Ruby で簡単に並列処理を行うための Ractor に多くの改善がありました。まず、Ractor::Port というクラスを加え、メッセージの送受信についのて問題を解決しました(ブログ記事)。また、Ractor.shareable_procによって、ProcをRactor間で共有しやすくしました。

性能面では、多くのデータ構造を改善し、グローバルロックに対する競合が大幅に減少し、並列処理性能を向上しました。また、Ractor 間で共有するデータを減らすことで、並列実行時の CPU キャッシュの衝突を減らしました。

Ruby 3.0 で experimental feature として導入されましたが、来年くらいには experimental を取りたいと思っています。

言語仕様の変更

  • *nilnil.to_a を呼ばなくなりました。**nilnil.to_hash を呼ばないのと同様です。[Feature #21047]

  • 行頭の論理二項演算子(||&&andor)は、ドット記法のように前の行を継続するようになりました。次のコードは同等です。

      if condition1
         && condition2
        ...
      end
    

    従来の書き方:

      if condition1 && condition2
        ...
      end
    
      if condition1 &&
         condition2
        ...
      end
    

    [Feature #20925]

コアクラスの更新

注: 特筆すべきクラス更新のみを記載しています。

  • Array

    • array.reverse_each.find より効率的な代替として Array#rfind を追加しました。[Feature #21678]
    • Enumerable#find をより効率的に実行する Array#find を追加しました。[Feature #21678]
  • Binding

    • Binding#local_variables は番号付きパラメータを含めなくなりました。また、Binding#local_variable_getBinding#local_variable_setBinding#local_variable_defined? は番号付きパラメータを扱わないようになりました。[Bug #21049]

    • 番号付きパラメータおよび “it” パラメータにアクセスするために、Binding#implicit_parametersBinding#implicit_parameter_getBinding#implicit_parameter_defined? を追加しました。[Bug #21049]

  • Enumerator

    • Enumerator.produce がオプションのキーワード引数 size を受け付けるようになりました。サイズには整数、Float::INFINITY、ラムダなどの呼び出し可能オブジェクト、または不明を示す nil を指定できます。省略時は Float::INFINITY です。

        # 無限列挙子
        enum = Enumerator.produce(1, size: Float::INFINITY, &:succ)
        enum.size  # => Float::INFINITY
      
        # サイズが既知/計算可能な有限列挙子
        abs_dir = File.expand_path("./baz") # => "/foo/bar/baz"
        traverser = Enumerator.produce(abs_dir, size: -> { abs_dir.count("/") + 1 }) {
          raise StopIteration if it == "/"
          File.dirname(it)
        }
        traverser.size  # => 4
      

      [Feature #21701]

  • ErrorHighlight

    • ArgumentError が発生した際に、メソッド呼び出し側(caller)とメソッド定義側(callee)の両方のコードスニペットを表示するようになりました。[Feature #21543]

      test.rb:1:in 'Object#add': wrong number of arguments (given 1, expected 2) (ArgumentError)
      
          caller: test.rb:3
          | add(1)
            ^^^
          callee: test.rb:1
          | def add(x, y) = x + y
                ^^^
              from test.rb:3:in '<main>'
      
  • Fiber

    • Kernel#raise と同様に Fiber#raise(cause:) 引数をサポートしました。[Feature #21360]
  • Fiber::Scheduler

    • 指定した例外でファイバを中断する Fiber::Scheduler#fiber_interrupt を追加しました。初期用途は、IO 操作が閉じられたときにブロッキング IO を待っているファイバを中断することです。[Feature #21166]

    • シグナル例外が無効なときでもスケジューラが処理を続行できるよう、Fiber::Scheduler#yield を追加しました。[Bug #21633]

    • 非同期 IO#close 用の Fiber::Scheduler#io_close フックを再導入しました。

    • IO 書き込みバッファを flush する際に Fiber::Scheduler#io_write を呼び出すようになりました。[Bug #21789]

  • File

    • カーネルとファイルシステムが対応していれば、statx システムコール経由で Linux でも File::Stat#birthtime が利用可能になりました。[Feature #21205]
  • IO

    • IO.select がタイムアウト引数として Float::INFINITY を受け付けるようになりました。[Feature #20610]

    • | で始まる IO クラスメソッドによるプロセス生成という非推奨挙動を削除しました。[Feature #19630]

  • Kernel

    • Kernel#inspect#instance_variables_to_inspect メソッドの有無を確認し、#inspect 文字列に表示するインスタンス変数を制御できるようになりました。

        class DatabaseConfig
          def initialize(host, user, password)
            @host = host
            @user = user
            @password = password
          end
      
          private def instance_variables_to_inspect = [:@host, :@user]
        end
      
        conf = DatabaseConfig.new("localhost", "root", "hunter2")
        conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root">
      

      [Feature #21219]

    • | で始まる Kernel#open によるプロセス生成という非推奨挙動を削除しました。[Feature #19630]

  • Math

  • Pathname

    • Pathname は default gem から Ruby のコアクラスに昇格しました。[Feature #17473]
  • Proc

    • Proc#parameters は匿名のオプション引数を [:opt, nil] ではなく [:opt] と表示するようになり、必須匿名引数の場合と整合しました。[Bug #20974]
  • Ractor

    • Ractor 間の通信のための新しい同期機構として Ractor::Port クラスを追加しました。[Feature #21262]

        port1 = Ractor::Port.new
        port2 = Ractor::Port.new
        Ractor.new port1, port2 do |port1, port2|
          port1 << 1
          port2 << 11
          port1 << 2
          port2 << 12
        end
        2.times{ p port1.receive } #=> 1, 2
        2.times{ p port2.receive } #=> 11, 12
      

      Ractor::Port は次のメソッドを提供します。

      • Ractor::Port#receive
      • Ractor::Port#send(または Ractor::Port#<<
      • Ractor::Port#close
      • Ractor::Port#closed?

      この結果、Ractor.yieldRactor#take は削除されました。

    • Ractor の終了待ちを行うために Ractor#joinRactor#value を追加しました。Thread#joinThread#value に相当します。

    • Ractor#join を実装するために内部で使われる低レベルインターフェイスとして Ractor#monitorRactor#unmonitor を追加しました。

    • Ractor.select は Ractor と Port のみを受け付けるようになりました。Ractor が与えられた場合は、その Ractor が終了すると戻ります。

    • Ractor はデフォルトポートを持ち、Ractor.sendRactor.receive で使用されるようになりました (Ractor#default_port を追加)。

    • Ractor#close_incomingRactor#close_outgoing は削除されました。

    • 共有可能な Proc / lambda を作るために Ractor.shareable_procRactor.shareable_lambda を追加しました。[Feature #21550] [Feature #21557]

  • Range

    • Range#to_set はサイズチェックを行うようになり、終端のない範囲での問題を防ぎます。[Bug #21654]

    • Range#overlap? は無限(非境界)範囲を正しく扱うようになりました。[Bug #21185]

    • 始点のない整数範囲での Range#max の挙動を修正しました。[Bug #21174] [Bug #21175]

  • Ruby

    • Ruby に関する定数を含む新しいトップレベルモジュール Ruby を定義しました。このモジュールは Ruby 3.4 で予約されており、今回正式に定義されました。[Feature #20884]
  • Ruby::Box

  • Set

    • Set は自動ロードされる stdlib クラスからコアクラスになりました。[Feature #21216]

    • Set#inspect は配列リテラル風の簡潔な表示になりました(例: #<Set: {1, 2, 3}> ではなく Set[1, 2, 3])。[Feature #21389]

    • Set#to_setEnumerable#to_set への引数指定は非推奨になりました。[Feature #21390]

  • Socket

    • Socket.tcpTCPSocket.new が初回接続のタイムアウトを指定するキーワード引数 open_timeout を受け付けるようになりました。[Feature #21347]
    • TCPSocket.new でユーザー指定タイムアウトが発生した場合、状況により Errno::ETIMEDOUT または IO::TimeoutError が発生し得ましたが、今後は一貫して IO::TimeoutError を発生させます(ただし Socket.tcp では同様の状況で Errno::ETIMEDOUT となる場合があり、OS レベルのタイムアウトではいずれの場合も Errno::ETIMEDOUT が発生する可能性があります)。
  • String

    • Unicode を Version 17.0.0、Emoji を Version 17.0 に更新しました(Regexp にも適用)。[Feature #19908][Feature #20724][Feature #21275]

    • String#stripstrip!lstriplstrip!rstriprstrip!*selectors 引数を受け付けるようになりました。[Feature #21552]

  • Thread

    • Kernel#raise と同様に Thread#raise(cause:) 引数をサポートしました。[Feature #21360]

Stdlib の更新

ここでは注目すべき機能変更のみを記載します。

その他の変更は以下のセクションに記載しています。また、前回バンドル版(Ruby 3.4.0)からの GitHub リリース履歴がある場合はそれも記載しています。

次の bundled gem が default gem から昇格しました。

次のデフォルト gem を追加しました。

  • win32-registry 0.1.2

次の default gem を更新しました。

次の bundled gem を更新しました。

RubyGems と Bundler

RubyGems と Bundler は Version 4 が同梱されています。詳細は次のリンクを参照してください。

サポートプラットフォーム

  • Windows

    • _MSC_VER 1900 より古い MSVC をサポート対象外としました。つまり Visual Studio 2015 以降が必須になります。

互換性に関する注意

  • Ractor::Port 追加に伴い、Ractor から次のメソッドを削除しました。

    • Ractor.yield
    • Ractor#take
    • Ractor#close_incoming
    • Ractor#close_outgoing

    [Feature #21262]

  • ObjectSpace._id2ref は非推奨になりました。[Feature #15408]

  • Process::Status#&Process::Status#>> を削除しました(Ruby 3.3 で非推奨)。[Bug #19868]

  • $SAFE のパスチェック(Ruby 2.7 で削除)に使われ、既に非推奨だった rb_path_check を削除しました。[Feature #20971]

  • “wrong number of arguments” の ArgumentError のバックトレースに、受け手のクラス/モジュール名が含まれるようになりました(例: bar ではなく Foo#bar)。[Bug #21698]

  • バックトレースに internal フレームが表示されなくなりました。C 実装メソッドも、他の C 実装と同様に Ruby ソースファイル上にあるかのように表示されます。[Bug #20968]

    変更前:

    ruby -e '[1].fetch_values(42)'
    <internal:array>:211:in 'Array#fetch': index 42 outside of array bounds: -1...1 (IndexError)
            from <internal:array>:211:in 'block in Array#fetch_values'
            from <internal:array>:211:in 'Array#map!'
            from <internal:array>:211:in 'Array#fetch_values'
            from -e:1:in '<main>'
    

    変更後:

    $ ruby -e '[1].fetch_values(42)'
    -e:1:in 'Array#fetch_values': index 42 outside of array bounds: -1...1 (IndexError)
            from -e:1:in '<main>'
    

Stdlib 互換性の注意

  • CGI ライブラリは default gem から除外されました。現在は次のメソッド向けに cgi/escape のみ提供します。

    • CGI.escape / CGI.unescape
    • CGI.escapeHTML / CGI.unescapeHTML
    • CGI.escapeURIComponent / CGI.unescapeURIComponent
    • CGI.escapeElement / CGI.unescapeElement

    [Feature #21258]

  • Set が stdlib からコアクラスへ移動したため、set/sorted_set.rb を削除し、SortedSet は自動ロードされる定数ではなくなりました。利用する場合は sorted_set gem をインストールし、require 'sorted_set' してください。[Feature #21287]

  • Net::HTTP

    • ボディ(本文)を持つリクエスト(例:POST、PUT)において、Content-Type ヘッダーが明示的に設定されていない場合に、デフォルトで application/x-www-form-urlencoded を自動設定する挙動が削除されました。もしアプリケーションがこの自動設定に依存していた場合、今後は Content-Type ヘッダーなしでリクエストが送信されることになり、特定のサーバーとの互換性が失われる可能性があります。 [GH-net-http #205]

C API の更新

  • IO

    • rb_thread_fd_close は非推奨になり、何もしなくなりました。C 拡張でファイルディスクリプタを Ruby コードに公開する必要がある場合は、RUBY_IO_MODE_EXTERNAL を使って IO インスタンスを作成し、rb_io_close(io) で閉じてください(これにより、その IO 上のすべての保留操作が割り込まれ、完了を待ちます)。ディスクリプタを直接閉じても保留操作は割り込まれず、未定義動作を招く可能性があります。言い換えると、同じファイルディスクリプタを共有する 2 つの IO オブジェクトの片方を閉じても、もう一方には影響しません。[Feature #18455]
  • GVL

    • rb_thread_call_with_gvl は GVL の有無にかかわらず動作するようになりました。これにより gem は ruby_thread_has_gvl_p を確認せずに済みますが、GVL の扱いには引き続き注意してください。[Feature #20750]
  • Set

    • Set の C API を追加しました。次のメソッドをサポートします。[Feature #21459]

      • rb_set_foreach
      • rb_set_new
      • rb_set_new_capa
      • rb_set_lookup
      • rb_set_add
      • rb_set_clear
      • rb_set_delete
      • rb_set_size

実装の改善

  • Class#new(例: Object.new)が全般的に高速化され、特にキーワード引数を渡す場合に効果があります。YJIT と ZJIT にも取り込まれました。[Feature #21254]
  • サイズプールの異なる GC ヒープを独立して成長させるようにし、一部のプールだけに長寿命オブジェクトがある場合のメモリ使用量を削減しました。
  • 大きなオブジェクトページでの GC スイープが高速化されました。
  • “Generic ivar” オブジェクト(String、Array、TypedData など)は、新しい内部 “fields” オブジェクトを使ってインスタンス変数アクセスを高速化します。
  • GC は内部の id2ref テーブルを初回使用まで保持しないようにし、object_id の割り当てと GC スイープを高速化しました。
  • Class / Module オブジェクトでの object_idhash が高速化されました。
  • より大きな多倍長整数でも可変幅アロケーションにより埋め込みのまま保持できるようになりました。
  • RandomEnumerator::ProductEnumerator::ChainAddrinfoStringScanner、および一部内部オブジェクトが書き込みバリア保護され、GC のオーバーヘッドを削減します。

Ractor

Ractor をより安定・高性能・実用的にするため多くの改善を行いました。これらにより Ractor 実装は実験的ステータスを脱する段階に近づいています。

  • パフォーマンス改善
    • 凍結文字列とシンボルテーブルが内部でロックフリーのハッシュセットを使用します。[Feature #21268]
    • メソッドキャッシュの参照で多くの場合ロックを回避します。
    • クラス(および generic ivar)のインスタンス変数アクセスが高速化され、ロックを避けます。
    • Ractor ごとのカウンタを用いてオブジェクト割り当てでの CPU キャッシュ競合を回避します。
    • スレッドローカルカウンタを用いて xmalloc/xfree での CPU キャッシュ競合を回避します。
    • 多くの場合 object_id 取得でロックを回避します。
  • バグ修正と安定性
    • Ractor と Thread の併用で起こり得るデッドロックを修正しました。
    • Ractor 内での require / autoload の問題を修正しました。
    • Ractor 間のエンコーディング/トランスコード問題を修正しました。
    • GC 操作やメソッド無効化に関する競合を修正しました。
    • Ractor 起動後にプロセスを fork する際の問題を修正しました。
    • Ractor 環境下で GC の割り当てカウントが正確になりました。
    • GC 後に TracePoint が動作しない問題を修正しました。[Bug #19112]

JIT

  • ZJIT
    • メソッドベースの実験的 JIT コンパイラ を導入しました。利用可能な場合、ZJIT は --zjit オプションまたは RubyVM::ZJIT.enable を呼び出すことで実行時に有効化できます。 Ruby をビルドする場合、ZJIT サポートを含めるには Rust 1.85.0 以降が必要です。
    • Ruby 4.0.0 時点で ZJIT はインタプリタより高速ですが、まだ YJIT には及びません。ZJIT の試用を推奨しますが、現時点では本番利用を推奨しません。
    • 目標は Ruby 4.1 で ZJIT を YJIT より高速かつ本番対応にすることです。
  • YJIT
    • RubyVM::YJIT.runtime_stats
      • デフォルトビルドでは ratio_in_yjit は利用できなくなりました。configure--enable-yjit=stats を付け、--yjit-stats で有効化してください。
      • すべてのコードが TracePoint により無効化された回数を表す invalidate_everything をデフォルト統計に追加しました。
    • RubyVM::YJIT.enablemem_size:call_threshold: オプションを追加しました。
  • RJIT
    • --rjit を削除しました。サードパーティ JIT API の実装は ruby/rjit リポジトリに移します。

より詳細な情報は NEWScommit logs を参照してください。

これらの変更により、Ruby 3.4.0から 3889 ファイルが変更され、 230769 行が追加され、 297003 行が削除されました

メリークリスマス、良いお年を、そして Happy Hacking with Ruby 4.0!

Download

  • https://cache.ruby-lang.org/pub/ruby/4.0/ruby-4.0.0.tar.gz

    SIZE: 23955109
    SHA1: 754e39e9ad122e1b6deaed860350bac133a35ed3
    SHA256: 2e8389c8c072cb658c93a1372732d9eac84082c88b065750db1e52a5ac630271
    SHA512: 688254e939b197d564e896fb951bc1abf07142f489e91c5ed0b11f68f52d6adb6b1f86616fe03f1f0bb434beeef7e75e158b9c616afb39bb34403b0b78d2ee19
    
  • https://cache.ruby-lang.org/pub/ruby/4.0/ruby-4.0.0.tar.xz

    SIZE: 18008368
    SHA1: 05ec670e86f84325c5353ef2f2888e53b6adc602
    SHA256: a72bacee9de07283ebc19baa4ac243b193129f21aa4e168c7186fb1fe7d07fe1
    SHA512: 2d5b2e566eaf70a5f3ea6ce6afc0611c0415de58a41336ef7a0b855c9a91eda9aa790a5f8b48e40a1eb9d50f8ea0f687216e617f16c8d040a08474f3116518a4
    
  • https://cache.ruby-lang.org/pub/ruby/4.0/ruby-4.0.0.zip

    SIZE: 29253204
    SHA1: 0b69f89d1d140157251c0d3a6032f6c45cdf81e8
    SHA256: 70cb1bf89279b86ab9a975d504607c051fc05ee03e311d550a5541b65e373455
    SHA512: a72e076ef618c0aeb9d20cf22e6fb12fda36809c0064ef0f98153b95a0bac257ef606342444a38f992c4594bf376a4d264686cf597463aa6f111220798784302
    

What is Ruby

Rubyはまつもとゆきひろ (Matz) によって1993年に開発が始められ、今もオープンソースソフトウェアとして開発が続けられています。Rubyは様々なプラットフォームで動き、世界中で、特にWebアプリケーション開発のために使われています。

最近のニュース

サイトのアイデンティティの再設計

サイトの包括的なデザインのアップデートを発表できることを嬉しく思います。今回の更新ではTaeko Akatsukaさんにデザインを担当していただきました。

Posted by Hiroshi SHIBATA on 22 Dec 2025

Ruby 4.0.0 preview2 リリース

Ruby 4.0.0-preview2 が公開されました。Ruby 4.0では、Unicodeバージョンの17.0.0へのアップデートなど様々な改善が行われています。

Posted by naruse on 17 Nov 2025

もっと読む...