« RubyCocoa on Ruby-1.9 の現状 | トップページ | Cocoa 入門サイト「Cocoa はじめの一歩」 »

2007.06.12

RubyCocoa の new を考える

RubyKaigi 自体の日記は書くの時間かかりそうなので、とりあえずこの件を先に。藤本さんのセッション中に irc でちょろっと出ていたけれど、RubyCocoa の Cocoa クラスにはインスタンスを生成する new メソッドがない。というかエラー。

 % irb -r osx/cocoa
 irb(main):001:0> OSX::NSURL.new 
 RuntimeError: use 'alloc.initXXX' to instantiate Cocoa Object
        from /Library/Frameworks/RubyCocoa.framework/Versions/A/Resources/ruby/o
 sx/objc/oc_import.rb:251:in `new'
        from (irb):1

これは Ruby と Cocoa オブジェクトの初期化の手続きや、initXXX のそれぞれに対応して Object#initialize() を調整するのが手間がかかるってあたりが理由(だと思う)。

でも Ruby なら new したいよな。ただでさえ Cocoa のメッセージ名長いし。で、考えてみたのだけれど、欲しいところから順に CocoaClass.new を定義していけばよいんじゃなかろうか。正月にリファレンスマニュアルの作業してて、クラスメソッド new を定義してあるのを見たときは驚いたけど、定義したからって問題があるわけじゃない。

Hash をキーワード引数的に受け取るのがいいのかな。たとえば、

 class OSX::NSView
   # - :frame : ビューの位置、大きさを NSRect で 
   def self.new(args = {})
     args[:frame] ||= NSMakeRect(...) # 省略されたら適当な初期値を
     self.alloc.initWithFrame(args[:frame])
   end
 end
 
 class OSX::NSWindow
   # - :contentRect
   # - :styleMask
   # - :bufferingType
   # - :defer
   # - :screen
   def self.new(args = {})
     args[:contentRect] ||= NSMakeRect(...)
     args[:styleMask] ||= NSTitledWindowMask & NSClosableWindowMask &
                          NSMiniaturizableWindowMask
     args[:bufferingType] ||= NSBackingStoreBuffered
     args[:defer] ||= true
     args[:screen] ||= nil # メインスクリーン
     self.alloc.initWithContentRect_styleMask_backing_defer_screen(...)
   end
 end

こんな感じ。適切な初期値を考えるのがちょっと大変かもしれないけれど、引数の多い初期化メソッドが少なくない Cocoa では有効かもしれない。初期値が気に入らなければインスタンスを生成した後で、setter で値を変更すればいいだけだし。

|

« RubyCocoa on Ruby-1.9 の現状 | トップページ | Cocoa 入門サイト「Cocoa はじめの一歩」 »