Hatena::ブログ(Diary)

きりかノート 2冊め

2014-04-09

[][]ruby-2.1, ruby-2.0.0をreadline-6.3に対応

port:readlineが6.3に更新されてたんだけど、それだとport:ruby21の拡張モジュールコンパイルエラーになるとのバグレポートがきてた。

rubyのtrunkは対応済み(bugs:9578)だったので、そっからパッチつくりだしてreadline-6.3と6.2の両方でtest-allが通ることを確認してコミット(r118728)。port:ruby20も同様に対応した。

ruby-1.9.3やruby-1.8.7のext/readlineは、今回問題になった型が使われていなかったので対応不要だった。

2014-02-25

[][]ruby-2.1.1, ruby-2.0.0-p451, ruby-1.9.3-p545に更新

MacPortsのパッケージをそれぞれ更新しました。各リリースの更新内容などについては公式のアナウンスを参照ください。

アナウンスにあるように、1.9.3は今後1年間セキュリティメンテナンス期間ののち、保守終了となります。

2014-02-21

[][]第64回 Cocoa勉強会に行ってきた(2/8)

会場はいつもの場所に戻って新宿伊藤ビルの貸し会議室

東京は大雪でしたが、来られるメンバーで開催。みんなおつかれした。

直前の天気予報見ながら、1週後ろにずらせばよかったかなあ。。とか思いましたが、次の週も雪でしたね。

以下発表など。内容的なことは勉強会のサイトのほうにレポートを書いたので、こちらは感想とか主観メインで。


発表「CoreDataとUndoiOS/Mac

CoreDataで親子関係にあるデータのUndoはbegin/endでグループ化しただけではうまくうごかないことがあり、カスタムクラスを割り当てたほうがよいよ、という話。

説明の中で、今ではCoreDataも指定すれば順序を保存できるようになってる(Ordered Relationships)と聞いて「へえー」というところ。やっぱみんな欲しいよね。


発表「Sony CameraRemoteAPI」Mac/iOS

SONYのレンズだけカメラ(DSC-QX100)のSDKを使用した操作について。Macのサンプルアプリでライブ画像をとってきて表示するデモ

こういうのも今はHTTPに乗せるの多いみたいね。


発表「リマインダーの繰り返しを自由に指定する」Mac

自分の発表。詳しくはエントリ書いたのでそちらを。

リマインダーの繰り返しをアプリから指定可能なもの以外も設定したい。EventKitから操作すると、いろんな繰り返しが設定できる。

見学の方から「RubyCocoaの2.0対応版はいつ出ますか?」という質問があったけど、、、うん。がんばるよ。


発表「DictionaryServicesを使ったMigemoみたいな逐次検索」Mac

DictionaryServicesを利用して、ひらがな→該当しそうな漢字のリストをとってきて全候補で検索、という話。ローマ字からひらがなはCoreFoundationAPIでいける(しかしなんでこんな関数OSにあるんだろ?)。

デモは、青空文庫の吉川三国志テキストをローマ字入力の"sousou"から"曹操"を検索。(ひらがなの「そうそう」などもヒットする)

もともとはmigemoみたいな逐次検索をめざしてたみたいなんだけど、まだそこまではいかず。てかCmigemo使ったほうがいいよ。きっと。


発表「SpriteKitを使ってみる」iOS

10.9とiOS7から利用可能なSpriteKitの概要と簡単なデモ。

physicsBodyの考え方がおもしろかった。たしかに物理シミュレーションと当たり判定は両方とも実体のあるモノの動作の表現なわけだ。

当日質問あったことだけど、その後MLでSpriteKit用のレベルエディタってないの?という話がちょっぴり盛り上がるなど。検索してみたとこ、開発してるって情報はぱらぱら見つかるけどまだ定番はないって感じかな。


発表「ゲームコントローラを使ってみました」iOS

iPhoneに装着するタイプのゲームコントローラのSDKの話。

キープレスの検出のサンプル見てて思ったんだけど、こういうのってObjective-Cならblocksで書いたほうがすっきり書けたりしないのかしらん。


次回の予定

次回は4/5(土)に今日と同じ会場で開催予定です。

見学の申し込みはconnpassの65回 Cocoa勉強会のページからどうぞ。

2014-02-08

[][]発表:リマインダーの繰り返しを自由に設定する (Mac)(2/08)

アプリで設定できるものでは足らないので、EventKit経由で自由に繰り返しを設定するよ、という話。

f:id:kimuraw:20140208181009p:image


あらすじ

  • リマインダーで「3週間ごとの繰り返し」を設定したい
  • それEventKitでできるよ
  • 実際にAPI操作して確認してみた。ほんとうにできるぜ!
  • RubyCocoaの宣伝


リマインダー

OS X/iOSに付属するAppleが提供するアプリで、

  • 指定の期日にアラームを鳴らしたり通知を表示させたりできる。
  • iCloudiTunes経由で複数のデバイスで同期できる。
  • 一定期間ごとの繰り返しを指定できる。

というもの。この繰り返しが、アプリ上では

  • 毎日
  • 毎週
  • 隔週(2週間)
  • 毎月
  • 毎年

の5種類のうちから選ぶようになっていて、それ以外の期間が設定できない。もしかしたらそういう操作があるのかもしれないけど、みつからなかった。


EventKitとリマインダー

以前の勉強会で他の人がEventKitの発表をしていて、「カレンダーやリマインダーを操作できる」という話があったのを思い出したので、それを試してみることに。

Mac Developer Libraryの”Calendar and Reminders Programming Guide ”をざっと読むと、"EKRecurrenceRule"が繰り返しをあらわすクラスのようだ。EKRecurrenceRuleのプロパティでは、繰り返し期間は

  • frequency: enum EKRecurrenceFrequencyであらわされる{年,月,週,日}の単位
  • intercal: 期間の数。数値。

の2つの組み合わせで表現されており、任意の期間が指定できそうだ。また、

  • daysOfTheWeek: 一週間のうちの曜日。複数指定もあり。

などずいぶん込み入った繰り返しも表現可能なようだ。

実際のところAPI上は可能でも、その繰り返しを受け入れるか、その繰り返しで次回の期限が設定されるか、はわからないところ。実際に試して確認したほうがよさそう。

動作確認の前にちょっとEventKitの構成を簡単に説明。リマインダーまわりは次のような構造になっている。

  • EKEventStore - リマインダー or イベントを保存しているもの。
  • EKCalendar - "ビジネス"、"買い物"などの種類。
  • EKReminder - 個々のリマインダー。繰り返しの情報はこいつが持っている。

ほぼアプリみたままね。


実際に繰り返しを持ったリマインダーを登録してみる

いちいちアプリをつくるのもめんどうなので、RubyCocoaとirbで直接操作することに。以下がデモのあんちょこ。実行時に「ターミナル.app」にリマインダーへのアクセス許可が必要なことに注意。(デモのとき無効にしてたの忘れてて、あれっ?となってしまった。。)

   require 'osx/cocoa'
   include OSX
   require_framework 'EventKit'

   # リマインダーのストア
   store = EKEventStore.alloc.initWithAccessToEntityTypes(EKEntityTypeReminder)
   # 追加するリマインダーをタイトルからとってくる
   calendars = store.calendarsForEntityType(EKEntityTypeReminder)
   calendar = calendars.find {|cal| cal.title == "テストだよ!"} # 環境によってタイトルは要調整

   # 新しいリマインダーを作成する
   reminder = EKReminder.reminderWithEventStore(store)
   reminder.title = "3週間ごとに実行する!"

   # 期限の日付を用意する
   due_date = NSDateComponents.alloc.init
   due_date.year = 2014; due_date.month = 2; due_date.day = 8
   due_date.hour = 18; due_date.minute = 30
   reminder.dueDateComponents = due_date

   # 繰り返しルール(3週間ごと)を作成する
   rule = EKRecurrenceRule.alloc.initRecurrenceWithFrequency_interval_end(EKRecurrenceFrequencyWeekly, 3, nil)
   reminder.addRecurrenceRule(rule)

   # 保存する
   result, err = store.saveReminder_commit_error(reminder, true)
   # おおっとエラー。メッセージをみてみましょう。
   err.localizedDescription

   # カレンダーの指定を忘れてましたね
   reminder.calendar = calendar
   result, err = store.saveReminder_commit_error(reminder, true)

   ## => リマインダーに保存されていること、指定の3週間ごとに実行されることを確認

これで作成したリマインダーを「完了」→「次の期限を確認」として、実際に3週間ごとの繰り返しで動作していることを確認した。めでたしめでたし。


もっと複雑な繰り返しを試してみる

"月2回の締め日(15, 月末)"。daysOfTheMonthでは負の値は末日からの日にちになるので、"-1"は月末になる。

   rule1 = EKRecurrenceRule.alloc.initRecurrenceWithFrequency_\
               interval_daysOfTheWeek_daysOfTheMonth_monthsOfTheYear_\
               weeksOfTheYear_daysOfTheYear_setPositions_end_(EKRecurrenceFrequencyMonthly,
                   1, nil, [15, -1], nil,
                   nil, nil, nil, nil)

"毎月第1、第3水曜日"。EKRecurrenceDayOfWeekを使うと「指定期間のn番目の指定曜日」が指定できる。次のようにすると、月々の第1水曜と第3水曜を対象にできる。

   days_of_week = [EKRecurrenceDayOfWeek.dayOfWeek_weekNumber(4, 1),
                   EKRecurrenceDayOfWeek.dayOfWeek_weekNumber(4, 3)]
   rule2 = EKRecurrenceRule.alloc.initRecurrenceWithFrequency_\
               interval_daysOfTheWeek_daysOfTheMonth_monthsOfTheYear_\
               weeksOfTheYear_daysOfTheYear_setPositions_end_(EKRecurrenceFrequencyMonthly,
                   1, days_of_week, nil, nil,
                   nil, nil, nil, nil)

それぞれ上記の繰り返しを適用したリマインダーを作成し、実際に意図したとおりに動作することを確認した。


まとめ

EventKitのEKRecurrenceRuleではかなり自由に繰り返し期間を設定できる。ただアプリ上は「カスタムの期間」となってしまい、登録後に設定がよくわからなくなってしまうのがちょっと残念。

RubyCocoaを使うと、アプリを作成しなくてもAPIの動作確認できて便利!(宣伝)。


RubyCocoaについて補足など

Mavericksでは"ruby"は2.0になっているので、今回と同様の確認をするには"/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/irb"を呼び出す必要があるので注意。現在、鋭意2.x対応中なので、自分のやる気を高めるためにも「まだ使えるポイントはあるんだぜ」アピールをしてきた。

2014-02-04

[][]BridgeSupportファイルにはどのくらいクラス定義があるか

こないだFoundation.bridgesupportにNSEnumeratorがないことがわかったので、実際どんなもんだろと確認してみた。

   % ack --hh '^@interface' /System/Library/Frameworks/Foundation.framework/Headers |
     cut -f2 -d\  | cut -f1 -d\: | sed -e 's/(.*)//g' |
     sort -u > hdr-classes-foundation.txt
   % ack --bs 'class\sname=' /System/Library/Frameworks/Foundation.framework/ |
     cut -f2 -d\' > bs-classes-foundation.txt
   % comm -13 bs-classes-foundation.txt hdr-classes-foundation.txt
   NSAutoreleasePool
   NSCachedURLResponse
   NSClassDescription
   NSCloneCommand
   NSCloseCommand
   NSCompoundPredicate
     :
   NSUniqueIDSpecifier
   NSUserNotificationCenter
   NSWhoseSpecifier
   NSXPCListener
   NSXPCListenerEndpoint
   % comm -23 bs-classes-foundation.txt hdr-classes-foundation.txt

ヘッダファイルのほうにのみあるクラスは70あって、NSEnumeratorのほかにNSErrorやNSNull、NSPipe、NSURLResponseなどよく使うクラスもある。ちなみにAppKitだと59で、わりとマイナーなViewが多くFoundationのカテゴリも含むからそんなでもない感じ。

ということで、BridgeSupportに定義されてるクラスをOSX.ns_importでロードしてやってクラスをRuby側に持ってくるという作戦は現実的じゃないみたい。

2014-02-01

[] RubyCocoa 今日のコミット 2014-02-01

やっぱイベントで内職ははかどる。。いや、話もちゃんと聞いてましたよ。

ruby-2.0|2.1まわりの作業。未コミットの修正含めれば、ruby-2.0, 2.1でもテストはだいぶ通るようになってきた。

  • "ruby/st.h"の判定をHAVE_RUBY_RUBY_HからHAVE_RUBY_ST_Hに変更。 (r2515)
  • ruby/objc/oc_import.rbのうち擬似オープンクラスの機能を別ファイルに分離、ruby-1.8のときのみ有効にするようにした。 (r2516)
  • ruby側のOSX::NSNumberに#to_iはあるものの#to_intがなくてうまくいかない箇所があったのでNSNumber#to_intを追加。 (r2517)
  • Hash#fetchのエラーがIndexErrorからKeyErrorになっててテストが失敗してたので対応。(r2518)
  • テストコードのRuby側で定義したObjective-Cサブクラスの参照がおかしかったので直した。擬似オープンクラスの仕組みでなんとなく動いてたもの。(r2519)

ruby-2.x対応で、現在目に見えてる課題はこのくらい。


擬似オープンクラス(と今日から呼ぶことにした)をどうするか

たとえば次のようなコードがあったとき、まだNSArrayがruby側に呼び出されていないと、単なるrubyのクラス定義になってしまう。

   class NSArray
     :
   end

これが定義済みのクラスの追加コードであるように振る舞うために、RubyCocoaではけっこうダーティなことをしちゃってる(「OSX.__rebind_umethod__ ってなに?」参照)んだけど、その機能がruby-2.0以降では動かないっぽい。

そもそも今動いてるのもちょっとあやしいので、2.0では該当機能は廃止する予定(てかr2516がその変更)。でも、「使う前に`OSX.ns_import :ClassName`しろ」ってのもコクな話だと思うので、できるだけ表面上は維持できるようにするつもり。

いちばん簡単な方法は、

なわけだけど、どうやって実装しようか。

たとえば、BridgeSupportファイルの読み込み時にクラスのエントリから実行させるなら、こんな簡単な修正でもruby-2.1で多くのテストが通るようになる。

   diff --git a/framework/src/objc/BridgeSupport.m b/framework/src/objc/BridgeSupport.m
   index 0e88b89..d24b544 100644
   --- a/framework/src/objc/BridgeSupport.m
   +++ b/framework/src/objc/BridgeSupport.m
   @@ -1606,6 +1606,8 @@ osx_load_bridge_support_file (VALUE mOSX, VALUE path)
              klass->instance_methods = st_init_strtable();

              st_insert(bsClasses, (st_data_t)class_name, (st_data_t)klass);
   +         // reveal Objective-C class to Ruby
   +         rb_funcall(mOSX, rb_intern("ns_import"), 1, rb_str_new2(class_name));
            }
          }
          break;
   diff --git a/framework/src/ruby/osx/objc/oc_import.rb b/framework/src/ruby/osx/objc/oc_import.rb
   index 5a86c9e..c4bec4a 100644
   --- a/framework/src/ruby/osx/objc/oc_import.rb
   +++ b/framework/src/ruby/osx/objc/oc_import.rb
   @@ -224,10 +224,6 @@ module OSX
        end
      end

   -  # Load the foundation frameworks.
   -  OSX.load_bridge_support_signatures('CoreFoundation')
   -  OSX.load_bridge_support_signatures('Foundation')
   -
      # create Ruby's class for Cocoa class,
      # then define Constant under module 'OSX'.
      def ns_import(sym)
   @@ -715,5 +711,10 @@ module OSX

      end

   +  # Load the foundation frameworks.
   +  OSX.load_bridge_support_signatures('CoreFoundation')
   +  OSX.load_bridge_support_signatures('Foundation')
   +  ns_import :NSEnumerator
   +
    end       # module OSX

ただ、BridgeSupportファイルには定義されていないクラスもあるようで、この修正でNSEnumeratorをns_importしているのもそういう理由。osx/objc/oc_attachments.rbでNSEnumeratorにメソッド追加してるので、その前にns_importしてやんなくちゃいけない。

フレームワークやライブラリのロード時にランタイムが知ってるクラスをぐるぐるとなめて、新しいクラスがあればns_importするって方法くらいしか思いつかない。たぶんパフォーマンス的にはさほど問題ないんだけど、なんかアホっぽい実装に感じる。もうちょっとスマートに実現できないかなあ。。


文字列のエンコーディング

rubyも文字列にエンコーディングを保持できるようになったんだけど、まだ考えてない。

FoundationのNSStringとrubyのStringのエンコーディングの変換表みたいのをつくって、オブジェクト変換時にそれを参照するって感じですかねえ。


ArgumentError: invalid value for Integer()

Stringを食わせてrb_Integer(str)してるとこがいくつかあるんだけど、そこでエラーになるっぽい。よくわからんのだけど、エラー箇所はだいたい押さえたので調べれば解決しそう。


tc_nsarray.rbを流すと落ちる

なんだろね。まだ調べてない。

2014-01-19

[] Interface Builderにカスタムクラスやアウトレットが表示されない

@casualconcさんからmentionで教えてもらった。Xcode 5.0.2の環境で、ruby側で定義したクラスやアウトレットがInterface Builderで表示されないとのこと。

ええとまあ、正直よく今まで動いてたなあ…って感じではあるのですが、内部的な仕組みとしてはこんなふうになってた。と思う。(このへん他の人がずっと担当してたからよーわからんのですよ)

  1. ユーザが、rubyコードを編集して保存する。
  2. Xcodeは編集されたコードについて、rb_nibtool.rbを呼び出す。
  3. rb_nibtool.rbはrubyコードを解析して、その結果をnibファイルのクラス定義に反映する。

"outlet rb_nibtool"あたりで検索してみると、MacRubyXcode 4.6.2で問題があったぽいissueがみつかった。MacRubyも同じような仕組みだったのでこのあたりから問題起きてたのかも。

で、課題は2つあって、

  • Xcodeからrb_nibtool.rbが呼び出されない。
  • rb_nibtool.rbがxib形式に非対応。

になる。前者はXcodeの動作なのでこっちから手は出せない。ただXcodeのプラグインを自作することで対処できるかも。後者はxibのファイル内容を調べてそれに対応する、て感じでしょうか。

ただ、これって両者とも将来的な不安要素が満載(Xcodeのプラグイン仕様やxibの内部形式の変更に追随する必要がある)なので、RubyMotion用のyury/ibのようにスタブのObjective-Cコードを生成してそれをXcodeに食わせる、という手法のほうがよさそう。

2014-01-05

[][] MacPortsにport:ruby21を追加

しました。2.1.0です。ちょっと確認に手間取ったりなどなどで遅くなりました。。

基本的に今までと同じです。

  • ruby2.1, rake2.1, gem2.1などバージョンのsuffixがつく
  • port select ruby ruby2.1などselectを使うと、suffixなしのバージョンで使える

今までとの差異としては


今回のパッチ

自分用にメモ。configureにパッチを当てています。Bug #9317: --with-opt-dirがLDFLAGS, DLDFLAGSに反映されない - ruby-trunk - Ruby Issue Tracking Systemへの対処のため、LIBPATHFLAGとRPATHFLAGを決めうちで設定するようにしています。

trunkは修正済みなので、次の2.1系リリースでマージされていれば、このパッチは不要になります。

2013-12-16

[][]第64回 Cocoa勉強会に行ってきた(12/7)

(書くの忘れてた。2014-02-26に公開)

会場は千葉県は松戸のSENDAI-YA。個人的には1年ぶりくらい?

以下発表など。


「ドキュメントベースアプリをTab化する」Mac

前回のマルチウィンドウの続き。PSMTabBarControlを使ったTab化について。

(感想)あー、懐かしいね>PSMTabBarControl。ふと思ったんだけど、MacでもApp Switcherスタイルでウィンドウ/アクティブドキュメントの切り替えをするアプリってないのかな?見た記憶がない。


Xcode Server みんなで使ってみる」Xcode

Xcode Server(OS X Serverが必要)でできること。

リポジトリサーバとCIハンズオンを参加者で実施しようとしたのだけれど、会場のネットワーク環境やサーバのディスク容量の問題などであまりうまくいかず。ハンズオン難しいよねえ。


「iOS向けのフレームワーク化に挑戦」iOS

MacのようにiOS用の.frameworkを作成する手順について。

(感想)podでダメな理由がよくわからなかった。あとで試してみよう。


「iOSアプリのデジタル署名」iOS

受託のときの納品を

  • 未署名のアプリを納品。
  • 納入先で署名してサブミット。

というようにしたいことがあり、その実現手順について調べた。Xcodeがなにをしているか、その際に必要になる情報などなどまとめ。

(感想)ほぼ完全なビルド済みアプリを作成して、それをもういちどXcodeでビルドというのはダメだった、というのが気になるところ。Xcodeの動作的にいけそうな気がするんだけどなあ。自分がアプリ公開するときがきたら試してみよう。


「Neerby Networking Multipeer Connectivity」iOS

iOS7からのMultipeer Connectivityについて。WIFIまたはBluetoothでデバイス間通信ができる。

  • サービスタイプの名前で接続する。
  • Gamekitと異なり、別アプリ間でも接続できる。
  • データ型などはないので、通信データの解釈はアプリで行う。
  • Mac上のシミュレータでは動作しない。試すにはiOSデバイスの実機が必要。

チャットアプリをデモ。iOSデバイス3台で簡易チャット。

(感想)今回いちばんおもしろかった。

  • 別アプリ間でも接続できる。
  • WIFI、Bluetoothを混在したネットワークを構築できる。

というところにすごく可能性を感じる。少人数の勉強会でのチャットなんかに使えたら便利そう。だとしたらMac版がほしいなあ。。

2013-12-06

git-svn使用時にgithubでContributionsが正しく表示されるようにする

えらくターゲットの狭い小ネタなんだけど、RubyCocoaの開発は手元ではgitでやってて、

  1. ローカルのgitで開発、コミット
  2. SourceForge.netのリポジトリにgit svn dcommitで反映
  3. 気が向いたときにgithubのミラーにpush

というようにしている。

ふと気付いたのだけど、けっこうコミットしてる期間にContributionsが緑にならないし、Commitsも自分のアイコンがでてない。gitのuser.emailも正しく設定してるしなんでだろ?と思って調べてみた。

その結果、svn dcommit時にユーザがsvnのものに書き換えられていて、user.emailが残っていない。ということがわかった。ミラーへのpush時は別の名前(メールアドレス)になっているから、github上では自分じゃないと判定されてしまっていると。

こんな感じ。@の後ろがよくわからん識別子みたいのになってる。

   Author: kimuraw <kimuraw@f4f36d40-9719-0410-9868-dde021a23eda>
   Date:   Thu Nov 28 14:41:28 2013 +0000

       Fix error with ruby-2.0

       - tc_bool.rb: require path of .bundle to relative.
       - tc_nsstring.rb: add magic comment for encoding.

       git-svn-id: https://svn.code.sf.net/p/rubycocoa/svn/trunk/src@2512 f4f36d40-9719-0410-9868-dde02

そんなときどうするかというと、ファイルを用意してsvn.authorsFileを指定しておけばよい。

   % cat svn-authors
   kimuraw = kimura wataru <kimuraw@i.nifty.jp>
   % git config svn.authorsFile svn-authors

これでちゃんと自分のコミットとしてgithub上で扱われるようになる。初回なんかはpush前にgit logあたりでちゃんとコミット者の名前が意図したとおりになっているかを確認したほうがよいかも。

2013-11-28

[] RubyCocoa 今日あたりのコミット 2013-11-28

ruby-2.0対応の準備とか。

  • 名前が未定義のときModule#nameがruby-2.0ではnilを、1.8では""を返すという差異によるエラーを修正。to_s入れただけ。(r2509)
  • ruby-1.8.4以前用のコードを削除。(r2510, r2511)
  • ruby-2.0でのエラーを修正。requireとeucなファイルへのマジックコメント。(r2512)

OSX.__rebind_umethod__ ってなに?

現時点でruby-2.0でテストを流すと次のエラーがでる。

   "/opt/local/bin/ruby2.0" -I../ext/rubycocoa -I../lib testall.rb
   /.../RubyCocoa.framework/Resources/ruby/osx/objc/oc_import.rb:781:in `__rebi
   nd_umethod__': wrong argument type UnboundMethod (expected Data) (TypeError)
       from /.../RubyCocoa.framework/Resources/ruby/osx/objc/oc_import.rb:7
   81:in `_register_method'

エラーそのものは書いてあるとおりで、__rebind_umethod__の実態であるところのmdl_osxobjc.mの関数にあるようにData_Get_Struct()に渡してるumethodがDataクラスじゃないからダメってこと。ちゅーか逆に、なぜ1.8だと通ってたのかがわからん。

   // FIXME: this is a silly hack.

   struct RB_METHOD {
     VALUE klass, rklass;
     // ...
   };

   static VALUE
   osx_mf_rebind_umethod(VALUE rcv, VALUE klass, VALUE umethod)
   {
     struct RB_METHOD *data;

     Data_Get_Struct(umethod, struct RB_METHOD, data);
     data->rklass = klass;

     return Qnil;
   }

それはそれとして、osx/objc/oc_import.rbの下のほうのObjectいじってるとこと、この__rebind_umethod__がなにをしているかを調べてみた。

RubyCocoaでは、オープンクラス的にObjective-Cのクラスにメソッドを追加することができる。

   module OSX
     class NSData
       def foo(args)
         :
       end
     end
   end

クラスメソッドを呼び出すときなどは、const_missingで処理できるけれど、上記のようなクラス定義のときにはconst_missingでなく新規のクラス定義になってしまう。これをメソッド定義時に強引にクラスを差し替えて実現している。それが上記の__rebind_umethod__での処理になっている。

2.0でこれどうするかって考えると、これはなくしたほうがよいよね。ぜったいヤバそうだし。

に、OSX.ns_importでクラスを実体化してやるってのが妥当な落としどころかなあ。

2013-11-24

[][] ruby-2.0.0-p353, ruby-1.9.3-p484に更新 (セキュリティ修正あり)

新しいバージョンがでてたのでMacPortsのほうも更新しました。セキュリティ修正があります。

2013-11-17

[]RubyCocoa-1.1.0 リリース!

しました。10.7用のdmgは、いるひとがいたら作るので言ってください。

今回の主な変更点は、

  • キャッシュの有効/無効を制御する$RUBYCOCOA_USE_OC2RBCACHEを導入。
  • standaloneify.rbが動かないケースを修正。
  • ruby-2.0でコンパイルが通るように。ただし動かない。
  • 10.5 Leopard以前のサポート終了。

あたりでしょうか。


リリースノート

NEWSファイルからだいたいコピペ

   == 1.0.7から1.1.0の変更点: 2013-11-17

   === 改良

     * Xcode 5の"Modules"に対応。
     * Objective-CとRubyオブジェクトのキャッシュをグローバル変数
       $RUBYCOCOA_USE_OC2RBCACHEで無効にできるようになりました。[Experimental]
       この機能は、NSTableViewのdelegateなどでときどきキャッシュとRubyのGCで
       不整合が発生してアプリケーションがクラッシュしてしまうケースを回避する
       ために使用することができます。
       たとえば次のようにすると、アプリケーションでキャッシュが無効にできます。

           # rb_main.rb
           require 'osx/cocoa'

           def rb_main_init
             :
           end

           $RUBYCOCOA_USE_OC2RBCACHE = false # <= add!
           rb_main_init

   === 修正

     * standaloneify.rbがruby-2.0またはrubygems-2.1でエラーになる問題を修正。
     * Objective-CのオブジェクトをObject#dupしたときSEGVする問題を修正。

   === 廃止された機能

     * Objective-Cのクラス"RubyCocoa"は廃止されました。
       Objective-Cからrubyを呼び出すには、ランタイム関数を使ってください。
       それぞれ対応する関数は次のとおりです。

         - bundleInitWithProgram:class:param: -> RBBundleInit()
         - applicationInitWithProgram:argc:argv:param: -> RBApplicationInit()
         - applicationMainWithProgram:argc:argv: -> RBApplicationMain()

     * NSString|Stringの"NKF"拡張ライブラリを使っているメソッドを廃止しました。

         - NSString.guess_nsencoding
         - NSString.guess_encoding
         - NSString.stringWithRubyString
         - NSMutableString.stringWithRubyString
         - String.nsencoding

   === 備考

     * Mac OS X 10.5 or earlier not supported.

ウェブサイトリニューアル

今までnanocで生成してた http://rubycocoa.sourceforge.net/ を、APIドキュメントつくるついでにyardに統一しました。APIのドキュメントもサイトに載せています。

素のスタイルなのでだいぶそっけない感じです。。


今後の予定

  • blocks対応
  • ruby 2.0対応
  • ドキュメントの拡充

あたりですかねえ。

podfileとかgemfileみたいのも導入したいけど、実装方針がぜんぜん固まってない。

2013-11-16

[] RubyCocoa 今日のコミット 2013-11-16

テーブルビューのスクロール時にクラッシュすることがあるの件の続き。

ということで、Objective-C -> Ruby オブジェクトキャッシュを無効にする方法を導入した。

キャッシュを無効にしたとき、Objecitve-Cのid型の値が同じで、RubyのVALUEのIDが異なる、というオブジェクトが生成されることになる。今まではキャッシュ経由で同じIDのVALUEを割り当てるようにしていた。(CF系など、もともとキャッシュ対象外となっているクラスもある)

ID値が異なっていることにより問題あるケースというのが思いつかなかったのだけど、Hash使ったときには同じオブジェクトとみなしてほしいだろうと考えたので、#hashや#eql?を再定義して内部のObjective-Cのid値に従うようにした。その作業中に、#cloneができるのは基本的にまずかろう(必要ならObjective-Cのcopy系メソッドを使うことを推奨)と思ってundefしたのと、NSURL#dupすると落ちるので直した。これ、メモリの確保をrb_define_alloc_func()で関数を指示してなくって、initializeで行ってるのが原因ぽいんだけど、なんでこれずっと直されてなかったんだろ…?RubyCocoaの初期開発時には、Rubyにrb_define_alloc_func()なかったからそのまんまになってたてことなのかな。

OSX::ObjCIDは、OSX::NSObjectなどのObjective-CのクラスのRuby界での親になっているクラス。

で、本題のキャッシュ無効の制御なんだけど、グローバル変数を使う形にした。OSX::RubyCocoaモジュールを導入してGC.enableみたいにしてもいいんだけど手間のわりにメリットがないなあと。

使い方は、初期値がtrueになってるのでfalseにするだけ。たとえば、rb_main.rbで

   require 'osx/cocoa'

   def rb_main_init
     :
   end

   $RUBYCOCOA_USE_OC2RBCACHE = false
   rb_main_init

としてやれば、そのアプリではキャッシュが無効になる。テーブルビューを使ったサンプルプログラムで、この手法で例のクラッシュが起きなくなったことを確認。

中の動作としては、キャッシュが無効にされたときに

  • 既存のキャッシュをすべて捨てる。
  • 新しいキャッシュへの登録を行わない。

ということになっている。再度trueにすればまた有効な状態で動作する。

2013-11-07

[] RubyCocoa 今日のコミット 2013-11-07

後者についてちょっと補足。RubyCocoaにはNKFを使ったユーティリティな機能があって、そいつらを削除した。具体的には以下のメソッド

  • OSX::NSString.guess_nsencoding
  • OSX::NSString.guess_encoding
  • OSX::NSString.stringWithRubyString
  • OSX::NSMutableString.stringWithRubyString
  • String.nsencoding

standaloneifyかけたときに、nkf.bundleがアプリケーションにパッケージされるのがなんかなあ、と思っていたのと、ruby-2.0対応時にどうせエンコーディングまわりを整備する必要があるのでこのさい整理しとくことに。

このメソッド、テストケース以外で使われてるの見た記憶がないし。