
株式会社Techouseでバックエンドエンジニアをしている、AsagaKoshoです。
Techouseではエンジニア総勢21名で、2026年4月22日〜24日に北海道函館市で開催された RubyKaigi 2026 に参加してきました。
この記事では、@tagomorisさんによる1日目のKeynoteセッション、"The Journey of Box Building" (発表要旨、スライド)についてご紹介します。
Ruby 4.0 の新機能、"Ruby Box"
2025年12月にリリースされた Ruby 4.0.0 では、Ruby Box と ZJIT の2つの大きな機能をはじめ、多くの新機能が追加されました。
そして、RubyKaigi 2026の幕開けは、そんな注目の新機能 Ruby Box についての基調講演からでした。

講演は以下の3部構成になっており、Ruby Boxのあらましから、詳細な内部実装、そして Ruby Box を作りはじめるに至ったストーリーまでを聞くことができた濃密な60分間でした。
1.What's Ruby Box?
Ruby Box とは何か、何が嬉しいのか
2.Tour of Ruby Box
Ruby VM 内部での Ruby Box の実装について
3.Road to Box Building
Box を作るに至ったtagomorisさん自身の個人史
ここでは、それぞれの内容について簡単に触れながら、私自身の学びとなったことをご紹介します。
What's Ruby Box?
昨年のRubyKaigiまでは "Namespace" と呼ばれていたこの機能でしたが、最終的に "Ruby Box"と命名され、Ruby 4.0.0で実験的な機能としてリリースされました。
Boxは、Rubyのプロセス内でクラスやモジュールを隔離する機能です。
柔軟にクラスやモジュールの拡張ができるのはRubyの強みでもありますが、その柔軟さがゆえにユーザーライブラリやgemでの実装が、Rubyプロセス全体に影響してしまうことがあります。
例えば、ユーザーライブラリで、以下のように組み込みライブラリのクラスである String を拡張するモンキーパッチを書くと、様々なライブラリの挙動に影響が出てしまいます。
class String def +(other) = "self:#{other}" end
そこで、このようなモンキーパッチを特定の空間内に隔離して、その空間外には影響を出さないようにするのがBoxです。下図は、ユーザーライブラリとアプリケーション・ライブラリを別のBoxに分離した例を示しています。同一プロセス内でも、モンキーパッチの影響は他のBoxに及びません。

スライド 15ページより抜粋
実際のユースケースとしては、以下のようなものが挙げられていました。
- テスト時のモックに利用するモンキーパッチを安全に書くことができる。
- 同一のRubyプロセス内で異なるバージョンのアプリケーション(依存するライブラリのバージョンが異なる)を並行稼働し、Blue-Greenデプロイのようなことができる。
Tour of Ruby Box
Ruby Box の発表は RubyKaigi 2024、RubyKaigi 2025 にもありました。これまでは Box ごとのクラス/メソッド定義の方法や、Box でファイルをロードする仕組みが扱われてきました。
今年は「どのBox内で実行されているのかの検出」(Current Box Management/Detection)が、セッションのメイントピックでした。
Ruby のコードは実行中いつでもクラスやメソッドを定義/参照できます。そのため「今どの Box にいるか」は、Rubyが動いている瞬間ごとに決定されます。
# main.rb (RUBY_BOX=1) b1 = Ruby::Box.new b1.require_relative("app") p b1::App.foo #=> Box b1 内の App.foo を呼ぶ
Boxでのモジュールの呼び出し方
ここで重要なのが、「Box の境界はファイルにあるが、ファイルが Box を決めるわけではない」ということです。同じファイルが、複数の異なるBoxによって呼び出されうるからです。
Current Boxを判定する仕組み
では、実行中の「今どのBoxにいるか」は、どのように判定されているのでしょうか。
Rubyのコードを実行するとき、内部では Control Frame というデータ構造がスタックに積まれていきます。メソッドを呼ぶたびに1つ積まれ、戻ると1つ降りていくイメージです。各Control Frameは「ENV」というローカル変数の置き場を持っており、そこに ME_CREF や SPECVAL といった特殊なスロットが含まれています。Boxの所属情報は、このENVに記録されているのです。
つまり「今どのBoxにいるか」を知るには、現在のControl Frameをたどって ENV を覗けばよいわけです。
ただし、これだけでは少し問題があります。例えば、以下のようにブロックの中で実行している場合はどうでしょうか。
def self.foo [:foo, :bar].map { it.to_s # ← この瞬間、どのBoxにいる? } end
ブロックは「呼ばれた場所」ではなく「定義された場所」のBoxで動くべきです。そのため、ブロック自身のFrameを見るのではなく、それを含むメソッドのFrameまで遡って判定します。
ここで活躍するのが「LOCAL」フラグです。
- LOCALなスコープ
- File、Class/Module、Methodの本体 → 自身でBox情報を持つ
- LOCALでないスコープ
- Block、eval、rescue → 外側のLOCALスコープから継承する
Current Boxを判定するアルゴリズムは、要するに「今のFrameから出発して、LOCALフラグが立ったFrameに到達するまで遡り、そのENVからBox情報を取り出す」という流れになります。
Bootstrappingの問題
ここで、もう1つ厄介な問題が出てきます。
- メソッド本体のFrameは、メソッド定義時にBox情報を持たせられる
- クラス本体のFrameも、クラス定義時にBox情報を持たせられる
- しかし、ファイルの一番上(TOP frame)は、誰がBox情報を書き込むのでしょうか。
ファイルがロードされた瞬間のFrameには、まだ誰もBox情報をマークしていません。これがBootstrappingの問題です。
解決策として、Ruby::Box#require が呼ばれた瞬間に、これからロードされるTOP frameにBoxの印を付ける仕組みが導入されています。具体的には VM_FRAME_FLAG_BOX_REQUIRE という新しいFrameフラグを立てることで実現されているそうです。
Kernel#requireをどうハンドルするか
さらにもう1つの問題があります。実際のアプリケーションコードでは、Ruby::Box#require ではなく Kernel#require を呼ぶことがほとんどです。そして、Kernel#require はRubyGemsによって上書きされています。
この場合、Boxの中でrequireを呼んでも、Boxの切り替えロジックが動かなくなってしまいます。
これに対する解決策が Ruby::Box::Loader の挿入です。Box内の Object クラスに Box::Loader を include させます。こうしておくと、Box内で require が呼ばれた際は必ず Box::Loader#require を経由します。そこで BOX_REQUIRE フラグを立てることで、「これからロードするファイルは現在のBoxのものだ」と印付けができるのです。
Ruby Box は Ruby VMの実行・ロード・メソッドディスパッチに、細かい設計判断が積み重なって実現されています。「Tour of Ruby Box は、Ruby VMの Tour でもある」というtagomorisさんの言葉が印象に残りました。
Road to Box Building
セッションの最後の3章は、技術的な話から一転して、tagomorisさんがRuby Boxを作るに至った個人史についてのお話でした。
意外だったのは、tagomorisさんが3年前のRubyKaigi 2023の時点では「自分はRubyに欲しい新機能なんてない」と感じていたとおっしゃっていたことでした。
転機となったのは、RubyKaigi 2023 Day 2で行われた@shioyamaさんの発表 "Multiverse Ruby" でした。tagomorisさん自身が以前書いていたLFAは、AWS Lambda Functionsを1プロセスで動かすアプリケーションサーバです。その動機が@shioyamaさんの発表内容と重なり、「これは自分が解きたかった問題だ」と気づいた瞬間だったそうです。
その日の夜、松本のバー "OLD ROCK" に @ffu_さん、@kakutaniさん、tagomorisさんが集まりました。後から@shioyamaさんも合流し、深夜まで議論を交わしたそうです。そこから Ruby Box の開発が始まりました。
そこからの3年間のタイムラインも紹介されました。
- 2023/5/23 (11日後): Namespace PoCの最初のコミット
- 2023/6/27 (46日後): Proposal #19744 "Namespace on read"
- 2023/10/25 (166日後): Ruby Association Grantに採択
- 2024/5/13 (約1年後): RubyKaigi 2024 "Namespace, What and Why"
- 2025/4/30 (約2年後): Pull Request提出
- 2025/12/25 (約2年7ヶ月後): Ruby 4.0リリース
- 2026/4/22 (約3年後): RubyKaigi 2026 Opening Keynote
「自分はRubyに欲しい新機能なんてない」と感じていた地点から、Ruby 4.0 で Box が公開されるまでの3年間を、tagomorisさんは淡々と振り返っていました。
最後にtagomorisさんが伝えていたメッセージは、以下の3つでした。
- THINGS HAPPEN SUDDENLY — モチベーションは、意図せず突然湧き上がるもの
- PARTIES, BARS, EVERYWHERE — それが起きる場所を作ってくれるオーガナイザーとスポンサーへの感謝
- TALK, BE MOTIVATED, ENJOY! — カンファレンスでは話して、刺激を受けて、楽しもう
カンファレンスは単に発表を聞く場ではなく、人と人が交わり、新しいモチベーションが生まれる場所である、というメッセージで講演は締めくくられました。
おわりに
Ruby Boxの技術的な深さと、それを作り上げた個人の3年間のストーリーが見事に組み合わさった、Opening Keynoteにふさわしい素晴らしい講演でした。
技術面では、Ruby Box が業務上の課題に新しい選択肢を提示してくれることがよく分かりました。モンキーパッチの隔離、テスト時のモック、複数バージョンのアプリケーションの並行稼働は、いずれも普段業務で扱う課題です。一方、Matz が構想する Packaging 機能を Ruby Box の上に実現するには、ActiveSupport との相性、フック箇所、メモリ使用量など未解決の課題も残っているそうです。今後の動向も追っていきます。
また個人的には、「自分にはもう貢献できることはない」と感じていた地点から外部の刺激をきっかけに動き始め、3年でここまで到達できるというストーリーに、強く励まされました。日々の業務で手を動かしているプロトタイプや小さな実装が、振り返ったときに意味を持ってくることは、決して珍しくありません。
RubyKaigi 2026の1日目の冒頭を飾るにふさわしい、技術とストーリーの両面で得るものの多いKeynoteでした。
Techouseでは、社会課題の解決に一緒に取り組むエンジニアを募集しております。 ご応募お待ちしております。