Rubyの開発版にNamespaceが導入されました。1つのRubyプロセスの中に分離された名前空間を提供することが目的の機能で、先日開催されたRubyKaigi 2025でも大きなトピックの1つとなっていました。
この記事では、Namespaceの目的と使い方を簡単に見ていこうと思います。より詳しく知りたい方は、記事末尾の参考資料を読んだり、ぜひ手元で動かしてみたりしてください。
Namespaceの目的
Namespaceの目的は、大きく以下の3つです。これはNamespaceが提案されているチケットに書かれています。
- ライブラリ間での名前の衝突を避けること
- 意図しないクラス定義の共有などを避けること
- 複数バージョンのgemを1つのプロセスからロードすること
試しに使ってみる
では、早速使ってみましょう。
開発版Rubyの準備
使うには最新の開発版のRubyが必要です。手元に開発版のRubyがない方は、rbenvを使って導入すると簡単でしょう。
$ rbenv install ruby-dev $ rbenv shell ruby-dev $ ruby -v ruby 3.5.0dev (2025-05-12T02:09:22Z master 4464cbe5cd) +PRISM [arm64-darwin24]
これで開発版のRubyの用意ができました。 ここからは、Namespaceの使用例を2つ紹介します。
例1: 同名のクラスを定義してみる
1つ目の例として、同名のクラスを定義してみましょう。app1.rb, app2.rb, そしてmain.rbの3つのファイルを用意します。
# app1.rb class App def hello puts "hello, app1" end end
# app2.rb class App def hello puts "hello, app2" end end
# main.rb class App def hello puts "hello, app main" end end ns1 = Namespace.new ns2 = Namespace.new ns1.require './app1' ns2.require './app2' ns1::App.new.hello ns2::App.new.hello App.new.hello
これら3つのファイルでは、どれもAppという同名のクラスを定義して、同名のhelloメソッドを定義しています。今までのRubyだと、これら3つのクラスは同じAppクラスだと認識されてしまい、どれか1つのhelloメソッドの定義しか使えませんでした。
Namespaceはこの問題を解決します。main.rbを見てみましょう。
main.rbでは、通常のrequireではなくNamespace#requireを呼んでいます。これによって、Namespace.newで作られたオブジェクトの下に、app1.rbやapp2.rbがrequireされます。そのためそれぞれのAppクラスは衝突することがなく、別のものとして扱えます。
実行結果を次に示します。なお注意点としてRUBY_NAMESPACE環境変数を定義して実行する必要があります。
$ env RUBY_NAMESPACE=1 ruby main.rb ruby: warning: Namespace is experimental, and the behavior may change in the future! See doc/namespace.md for know issues, etc. hello, app1 hello, app2 hello, app main
呼ばれているApp#helloメソッドがそれぞれ別のものであることが確認できました!
例2: オープンクラスをしてみる
もう1つの例として、オープンクラスを試してみましょう。integer_patch.rbとmain.rbの2つのファイルを用意します。
# integer_patch.rb class Integer prepend(Module.new { def +(rhs) super(rhs.to_i) end }) end puts "In integer_patch.rb" puts 42 + '42'
# main.rb ns = Namespace.new ns.require './integer_patch' puts "In main.rb" puts 42 + '42'
integer_patch.rb ではInteger#+ メソッドを変更してrhsをIntegerとして暗黙的に型変換した上で足し算をするようにしています。つまり、1 + '2'が3になるということです。なんて便利なのでしょうか!
しかしIntegerクラスへのオープンクラスは影響範囲がとても大きいです。Namespaceを使えば、この影響範囲を狭くすることができます。
今回のコードでは、integer_patch.rb, main.rbともに、puts 42 + '42'を実行しています。今までのRubyだとどちらのファイルでもこのコードは実行できてしまっていましたが、NamespaceがあればInteger#+にパッチが当たっているinteger_patch.rbの中でのみこの足し算が実行できるはずです。ということでコードを実行してみましょう。
$ env RUBY_NAMESPACE=1 ruby main.rb ruby: warning: Namespace is experimental, and the behavior may change in the future! See doc/namespace.md for know issues, etc. In integer_patch.rb 84 In main.rb main.rb:6:in 'Integer#+': String can't be coerced into Integer (TypeError) puts 42 + '42' ^^^^ from main.rb:6:in '<main>'
integer_patch.rbでは42 + '42'の実行が成功して84が表示されていますが、main.rbではこれがエラーになっているのがわかります!
まとめ
RubyのNamespace機能を軽く触ってみました。ぜひ手元でも色々試してみてください。
参考資料
- Feature #21311: Namespace on read (revised) - Ruby - Ruby Issue Tracking System
- Namespaceの議論がされているチケットです。
- ruby/doc/namespace.md at master · ruby/ruby · GitHub
- 公式のドキュメントです。
- State of Namespace - Speaker Deck
- Namespace, What and Why - Speaker Deck
- RubyKaigi 2025, 2024 でのNamespaceの作者であるtagomorisさんの発表資料です。
- RubyKaigi以外でもNamespaceについて話しているようなので、他の資料も興味があればどうぞ。