きりかノート 3冊め

おあそびプログラミング

サヨウナラ ns_import

[rubycocoa-devel:385] の件。

ちょっと前にふじもとさんから聞いた、lazy import による問題を修正。これがどんな問題かっていうと、

  • 現在の svn trunk (apple-unstable のマージ後) では、OSX::NSFoo とすると、const_missing を経由して、自動的に Cocoa のクラスが定義される(一種の autoload)
  • じゃあ、OSX.ns_import いらねーじゃん! -> そうでもない

どういう状況で OSX.ns_import が必要なのかを説明しよう。

   module OSX
class NSURL
def some_method()
end
end
end

このコードを書いた人は、きっとこんなことを考えるはずだ。

「これで OSX::NSURL クラスに some_method() という新しいメソッドを追加したぜ」

でも、そうじゃあない。ここでは OSX::NSURL という *新しい* Object のサブクラスが定義されて、そのクラスに some_method() というメソッドを定義しているだけだ。実際の Cocoa クラスの NSURL にメソッドを追加するには、class NSURL と宣言する以前に、OSX.ns_import :NSURL として名前空間OSX::NSURL を呼び出しておかないといけない。

これじゃ、autoload の価値も半減(は言い過ぎかも)だよな。

というわけで強引に解消。ここでの作戦は、

  • OSX::NSFoo といったクラスが定義されたら、ns_import したものと差し替え

というもの。ここでは、Object.inherited() をオーバーライドすることで実現した。詳しくは、svn の diff 参照。Module#const_set() でクラスの定義をフックできれば、もうちょっと簡単に書けたんだけどねえ。

もう、なんつーか Rubyメタプログラミングはいろいろできすぎてオソろしい。