これは、Rubyに仮想的なトップレベル名前空間を導入するためのNamespaceを提案します。NamespaceはRubyスクリプトかネイティブ拡張ライブラリかを問わず、ライブラリをグローバル名前空間から独立した形でrequire/loadします。
"Namespace on read"は次の2つの問題を解決し、また1つの問題について解決の道筋を提供します。
- ライブラリ(等)間での名前の衝突を避ける
- グローバルに共有されたライブラリ/オブジェクトの意図しない変更を避ける
- 依存ライブラリ間でのバージョン衝突を避ける(RubyGems, Bundlerの変更が必要)
# your_module.rb
module YourModule
end
# my_module.rb
require 'your_module'
module MyModule
end
# example.rb
namespace1 = NameSpace.new
namespace1.require('my_module') #=> true
namespace1::MyModule #=> #<Module:0x00000001027ea650>::MyModule (or #<NameSpace:0x00...>::MyModule ?)
namespace1::YourModule # similar to the above
MyModule # NameError
YourModule # NameError
namespace2 = NameSpace.new # Any number of namespaces can be defined
namespace2.require('my_module') # Different library "instance" from namespace1
require 'my_module' # require in the global namespace
MyModule.object_id != namespace1::MyModule.object_id #=> true
namespace1::MyModule.object_id != namespace2::MyModule.object_id
Namespace内でrequire/loadされたライブラリはモジュールやクラスのインスタンスをNamespace内に定義します。
"On read"はこの提案のキーとなるアイデアで、以下の点が重要です:
- 既存のライブラリには変更を要求しない(いくつかの限定されたケースを除く、後述)
- Namespaceを必要としないアプリケーションには全く変更を要求しない
- Rubyユーザーはアプリケーション全体のうち、必要な部分でのみNamespaceを有効にして使用する
- RubyユーザーはNamespaceを必要な部分で段階的に使いはじめられます
(この名前はデータ処理関連の"Schema on read"から取りました)
Namespace内でライブラリを読み込むとグローバルな名前空間のものとは別のライブラリとして読み込まれるため、メモリ消費量が増加する。(問題にならない範囲だと考えています)
Namespaceを用いて拡張ライブラリを衝突なく読み込む場合、拡張ライブラリをdlopen
する際にRTLD_GLOBAL
を指定しているのをRTLD_LOCAL
に変更する必要がある。このとき、読み込まれる拡張ライブラリ本体には問題は起きない。しかし、他の拡張ライブラリのC関数を呼び出す拡張ライブラリは、シンボルが見付からなくなって動作しなくなる。
これはRuby側から拡張ライブラリに対して他拡張ライブラリのシンボルを解決する機能を提供することで解決できる。該当する拡張ライブラリ側で対応が必要(Jeremyのコメントによると、適切なマクロの導入により前バージョンと互換性を保った形で対応できそう、とのこと)。
Namespace内での::Name
をグローバル空間のトップレベルとするべきか、Namespace内トップレベルとするべきか。
::ENV
は環境変数を指定してほしい::String
を指定できないとモンキーパッチするコードが書けない
またすでに存在するモンキーパッチのコード class String; def ....; end
をそのまま動くようにするべきかどうかを考える必要がある。これはNamespace内では class ::String; def ...; end
とさせるべきか?
Uh oh!
There was an error while loading. Please reload this page.