10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ruby::Box で複数のバージョンの Gem を同じ Ruby プロセスで動かす

Last updated at Posted at 2025-12-25

はじめに

本日 2025/12/25 (木) に Ruby 4 がリリースされました 🎉

Ruby::Box というクラスの定義を隔離できる新機能が実装されています。

今回はこの Ruby::Box を使って、複数のバージョンの Gem を同じ Ruby プロセスで動かしてみようと思います。

前提

Ruby 4 をインストールしておきましょう。以下は rbenv を使用して Ruby 4.0.0 インストールする例です。

$ git -C ~/.rbenv pull
$ git -C ~/.rbenv/plugins/ruby-build pull
$ rbenv install 4.0.0
$ rbenv local 4.0.0

例: 異なるバージョンの Rack を irb で動かす

Rack (rack) の Rack::Utils.byte_ranges メソッドの挙動が v3.0.9 から v3.0.9.1 で変わっているようです。それを確かめてみます。

事前に rack3.0.93.0.9.1 を両方インストールしておきます。

$ gem install rack -v 3.0.9
$ gem install rack -v 3.0.9.1

Ruby::Box を有効にするには RUBY_BOX=1 という環境変数を設定する必要があります。

$ RUBY_BOX=1 irb
/Users/quanon/.rbenv/versions/4.0.0/bin/ruby: warning: Ruby::Box is experimental, and the behavior may change in the future!
See https://docs.ruby-lang.org/en/4.0/Ruby/Box.html for known issues, etc.
irb(main):001>

まず、それぞれのバージョン用の Ruby::Box を用意します。
Ruby::Box はそれぞれ独立した $LOAD_PATH を持っており Ruby::Box#load_path でアクセスできます。そこに各バージョンの Gem の require すべきパスを追加します。

# Ruby::Box はそれぞれ独立した $LOAD_PATH を持っているので、
# それぞれに Gem のパスを追加する。
v3_0_9_0_box = Ruby::Box.new
full_require_paths = Gem::Specification.find_by_name('rack', '3.0.9').full_require_paths
#=> ["/Users/quanon/.rbenv/versions/4.0.0/lib/ruby/gems/4.0.0/gems/rack-3.0.9/lib"]
full_require_paths.each { v3_0_9_0_box.load_path << it }

v3_0_9_1_box = Ruby::Box.new
full_require_paths = Gem::Specification.find_by_name('rack', '3.0.9.1').full_require_paths
#=> ["/Users/quanon/.rbenv/versions/4.0.0/lib/ruby/gems/4.0.0/gems/rack-3.0.9.1/lib"]
full_require_paths.each { v3_0_9_1_box.load_path << it }

次に、それぞれの Ruby::Boxrackrequire します。

# 各 Ruby::Box で rack を require する。
# Ruby::Box ごとに Rack のバージョンが異なっている。
v3_0_9_0_box.require('rack')
v3_0_9_0_box::Rack::RELEASE
##=> "3.0.9"

v3_0_9_1_box.require('rack')
v3_0_9_1_box::Rack::RELEASE
#=> "3.0.9.1"

最後に、それぞれの Ruby::BoxRack::Utils.byte_ranges を呼び出してみます。

env = { 'HTTP_RANGE' => 'bytes=0-20,0-500' }
size = 500

# Ruby::Box ごと、つまり Rack のバージョンごとに
# Rack::Utils.byte_ranges の挙動が異なることを確認できた 🙆
v3_0_9_0_box::Rack::Utils.byte_ranges(env, size)
#=> [0..20, 0..499]
v3_0_9_1_box::Rack::Utils.byte_ranges(env, size)
#=> []

同じ irb (同じ Ruby プロセス上) で複数のバージョンの rack の挙動を確認することができました 😉

余談

  • まだ RubyGemsBundler には Ruby::Box を使って異なるバージョンの Gem を読み込んだり Gem のクラスを隔離したりするための専用の機能はないようです。これからの進化に期待です!
  • csvbigdecimal といった Gem でも同様のことを試しましたが、irb がクラッシュしたり思った挙動にならなかったり、まだまだ動作が不安定でした。
10
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?