NSString、NSArray、NSDictionary で Ruby のメソッドを使えるようにした
RubyCocoa 0.13.0 の新機能について。
いままでの RubyCocoa では、テキストフィールド上の文字列を操作するために、
s = @textField.stringValue # NSString を取得 s = s.to_s # いったん Ruby String に変換 s.gsub!(/\s/, '') # s をいろいろ操作 @textField.stringValue = s # NSString に自動変換して代入
のように書いていた。
これには、Cocoa の NSString がわりとシンプルで、それほど機能が多くないので、いったん Ruby の String にしたほうが楽に操作できるからという理由があった。(たとえば NSString には正規表現がない)
これを解決するために、String、Array、Hash のメソッドを NSString、NSArray、NSDictionary に全部移植することにした。そうすることで、Ruby の便利なメソッドをそれらのクラスでも使えて、さらに変換の手間やコストも省けるという一石二鳥になる。
Array と Hash については、すんなりと完了。
String については、Ruby の String が byte index なのに対して、NSString は character index という違いはあるが、途中まではスムーズに進んだ。ここらへんは、ruby 1.9 の m17n の動きと JRuby が参考になった。
問題は正規表現。ruby 1.8 内蔵の正規表現は UTF-16 を扱えないので、マッチした結果を character index で返すことができない。これができないと、=~ と match を実装することができない。
そこで、Oniguruma を取り込み、UTF-16 でマッチして character index を返すところまで作ってみたけど、$~ に MatchData クラス以外のオブジェクトを代入できないことがわかって挫折。MatchData は ruby の内部でしか作れないように、継承しても new できないようになっているらしい。
そうすると、残る方法は ruby 内蔵の正規表現でマッチして、返ってきた MatchData の全メソッドを特異メソッドで上書きして byte index → character index の変換をするくらいだろうけど、この方法はさすがに効率が悪そうなのであきらめることに。ruby 1.9 では、うまく解決できるだろう。