Ruby 4.0.0 で Pathname と Set が組込みクラスになるとのこと。
参考:Ruby 4.0.0 preview3 リリース
pathname や set の gem は読み込めるのだろうか?
なお,本記事の執筆にあたって,以下の二つのバージョンの Ruby を用いた。
- ruby 3.4.8 (2025-12-17 revision 995b59f666) +PRISM [arm64-darwin25]
- ruby 4.0.0preview3 (2025-12-18 master cfa3e7cf75) +PRISM [arm64-darwin25]
これまでの pathname
pathname は,Ruby 3.4 系では標準添付ライブラリーであった。
そのため,
- 使うには
require "pathname"が必要 - しかし,とくにインストールする必要はない
であった。
ただ,gem の形で提供されているので,Ruby に添付されているもの以外のバージョンも,インストールして使うことができる。
これまでの set
私の認識では,Ruby 3.4 系の set は
- 標準添付ライブラリーである
- ただし pathname などと違い,
requireしなくても使えるようになっている
であった。
しかし,今改めて Ruby 3.2.0 のリリースノート を見ると,
Setはrequire "set"を実行しなくても使用できる組み込みのクラスとなりました。 [Feature #16989] この機能はSetを参照した時、またはEnumerable#to_setを呼んだ時に有効となります。
とある。
require 不要になったのは Ruby 3.2 のときということだ。
それはいいのだが,ここで既に「組み込みのクラス」という表現が使われている。
もう一度 4.0.0-preview3 のリリースノートを見ると,こちらは
Setは autoload される標準ライブラリのクラスではなく、組み込みクラス (core class) になりました。 [Feature #21216]
となっている。
「組み込みのクラス」と「組み込みクラス (core class) 」は違うのだろうか? 用語が混乱しているのだろうか。
ともあれ,set は gem として提供されており,Ruby 3.4 系では Ruby に添付されていないバージョンの set をインストールして使うことはできる:
p RUBY_VERSION # => "3.4.8"
p Set::VERSION # => "1.1.2"
p RUBY_VERSION # => "3.4.8"
gem "set", "1.1.0"
p Set::VERSION # => "1.1.0"
p RUBY_VERSION # => "3.4.8"
Set # とくに何もしないが,Set を参照する
gem "set", "1.1.0"
# => 'Gem::Specification#check_version_conflict': can't activate set-1.1.0, already activated set-1.1.2 (Gem::LoadError)
Ruby 4 で gem は読み込めるのか
ここからが本題だ。
組込みクラスになってしまうと,gem で提供される pathname や set は使えなくなるのではないだろうか?
Ruby 4 で実験的に導入された Ruby::Box によるネームスペースを使えばひょっとして可能なのかとも思ったが,どう試せばよいかも分からなかった。
pathname
Ruby 4.0.0-preview3 で,gem 指定した pathname の require を試みる。
なお,以下の実験で,RUBY_VERSION が "4.0.0" を返しているが,使用したバージョンはプレビュー版である。
p RUBY_VERSION # => "4.0.0"
p Pathname::VERSION # => "0.4.0"
gem "pathname"
require "pathname"
# =>
# /Users/XXXXX/.rbenv/versions/4.0.0-preview3/lib/ruby/gems/4.0.0+1/gems/pathname-0.4.0/lib/pathname.rb:17: warning: already initialized constant Pathname::VERSION
# <internal:pathname_builtin>:194: warning: previous definition of VERSION was here
# /Users/XXXXX/.rbenv/versions/4.0.0-preview3/lib/ruby/gems/4.0.0+1/gems/pathname-0.4.0/lib/pathname.rb:36: warning: already initialized constant Pathname::SEPARATOR_LIST
# <internal:pathname_builtin>:312: warning: previous definition of SEPARATOR_LIST was here
# /Users/XXXXX/.rbenv/versions/4.0.0-preview3/lib/ruby/gems/4.0.0+1/gems/pathname-0.4.0/lib/pathname.rb:37: warning: already initialized constant Pathname::SEPARATOR_PAT
# <internal:pathname_builtin>:313: warning: previous definition of SEPARATOR_PAT was here
# /Users/XXXXX/.rbenv/versions/4.0.0-preview3/lib/ruby/gems/4.0.0+1/gems/pathname-0.4.0/lib/pathname.rb:43: warning: already initialized constant Pathname::ABSOLUTE_PATH
# <internal:pathname_builtin>:323: warning: previous definition of ABSOLUTE_PATH was here
p Pathname::VERSION # => "0.4.0"
これによると,
-
gem "pathname"までは問題ない - そのあと
requireするとPathname::VERSIONなどの定数が既に定義されている,と警告が出る -
requireの前後でPathname::VERSIONの値は変わらない
のようだ。
警告であってエラーではなく,鬱陶しいだけで動作には問題ないのかもしれない。
Gemfile と Bundler を使っている場合,警告は Bundler.require の時点で出る。
なお,gem "pathname" せずに require "pathname" すると何も起こらない。
以上の実験では,pathname のバージョンを指定していなかった。
バージョンを指定するとどうか。
先ほどの検証コードで
gem "pathname"
を
gem "pathname", "0.3.0"
に変えてみた(pathname 0.3.0 はインストールしておく)。
すると,
-
require前のPathname::VERSIONは"0.4.0" -
require後のPathname::VERSIONは"0.3.0" - 警告は同様のものが出たが,警告が出るライブラリー箇所は pathname 0.4.0 のファイルから 0.3.0 のファイルに変わった(まあ当然)
という点が違っていた。
Bundler を使った場合(Gemfile に gem "pathname", "0.3.0" を記述)も同様であった。
set
set も同じようにやってみようとしたが,Ruby 4.0.0-preview3 では Set::VERSION が定義されていないらしく,バージョンを確かめることすらできなかった:
p RUBY_VERSION # => "4.0.0"
p Set::VERSION
# => uninitialized constant Set::VERSION (NameError)
これは,gem メソッドで set gem のバージョンを指定して require しても変わらない:
p RUBY_VERSION # => "4.0.0"
gem "set", "1.1.0"
require "set"
p Set::VERSION
# => uninitialized constant Set::VERSION (NameError)
上記コードで,require ではエラーも警告も出ない。
ここが pathname と大きく違うところ。
Bundler を使った場合も同様だった。
set gem では,バージョン 1.1.0 でも 1.1.2 でも,Set::VERSION は定義されている。
- https://github.com/ruby/set/blob/v1.1.0/lib/set.rb#L219
- https://github.com/ruby/set/blob/v1.1.2/lib/set.rb#L227
この定数が参照できない,ということは,Ruby 4.0.0-preview3 では Bundler を使っても gem 版の set ライブラリーは使えない,ということなのかもしれない。
まとめ
Ruby 4.0.0 の,あくまでプレビュー版についてだが,以下のようにまとめられるかと思う。
pathname
-
require無しで使える - gem のバージョンを指定して
requireすることもできる - その場合,
Pathnameクラスの定数の上書きに関する警告が出る
別バージョンの pathname を require しても,Pathname クラスが入れ換わるわけではなく,上書きされるだけだと思う。
だから,組込みのほうに仮に xxx というメソッドがあったとして,その xxx を持たないバージョンを require したとしても,xxx が消えたりはしないのではないかと思う。
そうだとすれば,これが問題を引き起こすこともありうるのではないか。
set
- gem 版には存在する
Set::VERSION定数が存在しない -
require無しで使える - set gem を
requireすることはできないぽい(requireでエラーは出ないが,gem 版が読み込まれたようには見えない)