さっき「デフォルトのRubyから入れたコマンドを上書きされても困るし」って書いたけど、しっかり上書きされてました。これを使えば上に書いたような気持ち悪い書き換えはしないで済むみたいだ。さっき書き換えたところは全部元に戻し/usr/bin/baconを/usr/local/bin/macbaconにrenameし再度/usr/bin/gemの方でBaconをインストールした。言うわけで、デフォルトのRuby(/usr/bin/ruby)を使ってる人はmacgemの実行は気を付けた方がいいみたい。macgem自体は今殆どのgemがインストール時にコケるし、デフォルトのRubyはバージョンが若干古いので基本的には自分でbuildして/usr/local/binあたりかMacPortsから/opt/local/binあたりに入れてると思うので、そんなに困ることはないかもしれないけど、念のため。おまけBaconってなんだろう、ってググったら当然ベーコンに関する情報がヒットするんだけど、Google先生がなんか妙なものを拾ってきた。右端の変態、あんた何やってんだ。Tweet2008年09月25日Safariをなんとかしたい最近Objective-Cばかり書いてるナマケモノです、どうもこんばんは。Cocoaに始めて触れたときはこれで仕事になるとか思ってもなかったけど世の中わからないものだなー。ダメな子なので可愛かったりするのだけどもiPhoneアプリの開発もそろそろ佳境に入ってきてるのだけど、つくづく悩まされてるのがWebViewの不安定さ。実はなかなか使い勝手は良くて、Safariもどきとかならサクっと作れちゃうし、Webサービスと連携するアプリにしても困ったらサイトに行ってログインしてもらえばいいや、とか思ってたのだけど、いかんせん落ちまくるのがいただけない。Safariが駄目なんじゃないんだ。WebViewがそもそも駄目っぽい。mobile端末向けのWebUIってあんまり興味なかったんだけど(正直PC向けのページ見りゃいいじゃん、と思ってた)、ちょっとアレら向けに徹底的に最適化したUIを作らなきゃだめだなと思ってるところ。WebViewで楽できないとわかった以上、ついつい後回しにしがちなAPIを口実付けて整理しなおして、ネイティブアプリはネイティブアプリで完結できるようにしないとだなぁ。アプリのリリースができて一段落したら、モバイルの高機能端末向けのUIとAPIについてちゃんと考えたい。ブログとかクリップとか、ね。あと全然関係ないけどARToolKitの本買った。最近浮気しすぎだなー。今のうちにインプットできるだけインプットしとかないと。Exporter作りの続き。Invalidとしか返ってこなかった。Rubyでだったらサクっと書けたんだけど、CocoaでSHA1とかBase64とか結構面倒臭い。その辺で挫けかけたので一週間ほど放置してたんだけど、ググったらopensslのライブラリでやればいいじゃんってことがわかった。こんな感じでNSStringとNSDataにメソッドを生やしてみた。あとはXcodeのビルドオプションで「その他のリンカフラグ」に「-lcrypto」と追加してコンパイルしてやるだけ。buff;}@endObjective-Cなので見慣れない[]とか@とか入ってるけど、中身をよくよく見るとどう見てもCです。Cのコードやライブラリをそのまま転用できるのは素敵だなぁ。Objective-Cで便利なフレームワークとか見つけられなくてもCで探せば大概ある。Exporterに取り掛かってもいいんだけど、どっちかというとフレームワーク作りに興味が向き始めた。livedoorの各種サービスのAPIをCocoaから簡単に使えるようにするフレームワークでも作ろうかなぁ。Tweet2008年03月22日iPhotoプラグインを作りたいここのところ久しくObjective-Cをいじってなかったので、急にCocoaと戯れたい衝動に駆られた。iPhotoライブラリのExporterを作ろう、と思い付きでいろいろ調べてみた。iPhotoとかろくに触ったことないけど、Objective-C+Cocoa環境だと、動的にロードしたバンドルでランタイムのクラスを書き換えるとかもできてしまうので、既存のアプリに新しい機能を付けるとかが比較的簡単にできる。その気になれば(Cocoaアプリでさえあれば)どんなものにでもプラグインを作れるので、まぁなんとかなるだろと楽観的発想をしてみる。Labさんとこの一連の記事とそのリンク先。iPhotoには組み込みで写真のExporterを追加できる機能があるらしく、思ったより簡単にできそう。大雑把に言うと、「Exporterのプロトコルに準拠したバンドルを作って、拡張子を.iPhotoExporterにして、/Applications/iPhoto.app/Contents/PlugIns以下につっこむ」などすればいいらしい。元記事は詳細に作り方が書いてある上サンプルコードもあって素敵なのだけど、上で挙げた記事の通り、若干内容が古い。Leopard+iPhoto'08環境で使えるプラグインを作りたいので、自力でclass-dumpを使ってクラスを調べあげてExportPluginProtocolのヘッダファイルを作るところから挑戦することにする。これがなかなか厄介で、まずここで挫折しかけた。ヘッダファイルを作りはじめてはみたものの、何かサンプルコードの時点から大分増えたり減ったりしてて何が必要なのかわからないし、クラスやプロトコロルの定義はともかくCの構造体の定義とかまではちゃんとはdumpできない。途方に暮れかけながらExportPluginProtocolとかExportImageProtocolとかでググってたら、GoogleCodeにiPhotoPluginのプロジェクトがあるのを見つけた。欲しかったヘッダファイル全部ある。現在の環境で動くサンプルが作れる。お陰で「書き出し」メニューの中にカスタムビューを追加するだけのプラグインを作れるところまでは出来たので、あとは写真共有サイトのAPIを叩くロジックを書くだけ。これは単にHTTPでGETとかPOSTとかするだけなのでそんなに難しくない。Cocoaは面白いな。Tweet2008年01月13日NSCollectionViewCoreDataにつっこんであるデータを表示するViewを作ろうといろいろ試行錯誤してて、せっかくCoreDataでデータを管理してるのにいちいちそれを操作するコントローラを作るってのもなんだか泥臭いなと思ってたんだけど、調べたらちゃんとそれ専用のViewがあった。それがNSCollectionView。使い方は簡単InterfaceBuilder上でNSCollectionViewを配置すると、一緒にNSCollectionViewltemとNSViewが作られる。NSCollectionViewのBindingを設定する。entityを管理している)NSArrayControllerのarrangedObjectにBinding。Path」は空のまま。Indexes」をNSArrayControllerのselectionIndexesにBinding。Path」は空のまま。Item」は既にOutletが設定されているので、特に変更することはない。自動で作られた「View」はNSViewのインスタンスなので、カスタムビューを使う場合はこれのクラスを変更しておく。「View」に表示したいものをぽんぽん置いてく。配置した各項目のBindingを設定する。Item」にBindingする。Path」は「representedObject.属性名」になる。こんな感じで設定をすると、「CoreDataからデータをとってくる」→「そのデータをビューにはめこむ」→「スクロールビューに表示」までやってくれる。ここまででコーディング一切なし。残念ながらこれを使うとLeopardでしか動作しなくなっちゃうのだけど、これはかなり強力!CoreDataとCocoaBinding情報が少ないもんで何か難しいものと思われて敬遠されがちなんだけど、慣れてしまえばこれほど楽なものはない。データの扱いだとかUIの構築なんていう面倒なところを殆ど自作しなくてよくて、しかもそれが標準で使える機構だけでできるってのが素敵だよなー。参考にした記事を書いた人もTwitterクライアントを作ろうとしてCoreDataを弄ってらっしゃるのね。正月休み中に形にするぞと息巻いてRubyCocoaのtwitterクライアントを作ってるのだけども、主にtwitterと関係ないところでハマってる*1。モデルの管理とIBとの連携が楽になると思って当初からCoreDataを使ってるんだけど、結構煩雑というかやぼったいというか。オブジェクトの追加は楽にできるんだけどオブジェクトの取得が面倒臭いんだよなぁ。毎回NSFetchRequestを作ってNSEntityDescriptionを取得して...という処理を書くのがダルかったので、AR風のラッパを作ってみた。ベースのクラスを継承してモデル名と同名のクラスを作ると、そいつの操作が裏でCoreDataの操作になってるようなやつ。findとかdeleteとか、あとアクセサメソッドは定義しないでも勝手に拾ってよきにはからったりするとか、その辺は実装した。うーん、でも、このアプローチに自信が持てない。なんか車輪の再発明な気がしてならないし、多段ラッパになってて処理の効率悪そう。勉強目的だから再発明上等だしtwitterクライアント程度でそんなにパフォーマンス気にすることない気もするけども...。RubyCocoaのdefine_wrapperとかARの拡張とかその辺りを補完するようなフレームワークを作れればいいんだけど。「CoreDataで管理してるデータは、正常終了時に自動保存されるのだけど、どこでどう処理されてるのかわからない」テンプレートで自動生成されたAppDelegate.rbの中読んだらちゃんと書いてあった。applicationShouldTerminateメソッドの中で、managedObjectContextにsaveメッセージを送ってるのがそれですね。そこ以外ではデータの保存処理をしてないので、長時間つけっぱなしにしといて異常終了したりするとその間のログが全部ふっとぶのでどこかで定期的にsaveするようにしとかないとだ。そもそも保存されなくても大して困らないけど。使えるものは使っておけと。IBのチュートリアル書こうと思ってたけど、むしろ俺自身が嵌ってるので書けそうにない。カスタムビューの作り方とか画像の扱いとかわかんないことだらけ。Objective-CやRubyCocoaはわからなくても、昔の資料から類推したりソース読んだりすればなんとでもなるんだけど、InterfaceBuilderの使い方は独力ではキツい。バージョン違うと資料が役に立たないし。今他のアプリのソース見て参考にしてるけど、誰か詳しい人がいたら助けて欲しいっす。キーバリューコーディング主にMVCのうちのCとVのバインディングに活躍してるキーバリューコーディングだけど、RubyCocoaと結構相性がいい。key)とかしてやるだけでいいので、ラッパを作るのがすごい楽だった*2。いいから頑張れ俺とかなんとか文章でいくら書いてもしょうがないので、作ったもの晒してみんなにツッコミ入れてもらった方が早い。*1:二重の意味で*2:具体的に言うとARでいうところのcreateあたりがまさにそう。name.to_s)とかやると後はよきにはからってくれるので、その辺も大して考えずに書けた。Tweet2008年01月02日Ruchetta(仮)とCoreDataRubyCocoaを極めるプロジェクト中でtwitterクライアントを作るという話が出てたので、正月休み中にみんなでいじって遊べる程度に動くものを作ってしまおうと目下がりがり書いてる最中なのですが、なかなか楽しいね、RubyCocoa。CoreDataを活用してやろうと、HMDT本やリファレンスと格闘してました。CoreDataってなんぞ?ってレベルからのスタートだったので結構苦労したのだけども、CoreDataってのは要はCocoaアプリ中で簡易DBとO/Rマッパーを使えるようになるフレームワークなんだね。ActiveRecord+pstoreやsqlite、みたいなもんだと言っていいのかな。Xcodeのモデリングツールでデータの定義をしておけば、勝手にDBとラッパオブジェクトを作ってくれるのでモデルクラスのとこのコーディングが格段に減る。モデル同士の関連もモデリングツールで作れるし、InterfaceBuilderとの連携でコントローラ部分も自分で作る必要がないので、簡単簡単。RubyCocoaから使う場合はCocoaから使う場合と若干構成が違うので最初躊躇ったけども。自分へのメモの意味でも、Xcode3でRubyCoca-CoreDataアプリを作る際のIBチュートリアル記事をあとで書いとこう。ちなみに、twitterのデータの読み書きはこんな感じまずはデータの新規作成。'るこたん'これでるこたんの情報がCoreData経由で使えるようになる。実はこの時点では「るこたんの情報が管理対象になった」だけで、自分でデータの保存処理をするか、CoreDataApplicationテンプレートからプロジェクト作ってるとアプリの正常終了時に自動で保存処理が呼びだされる*1か、そのタイミングで初めてファイルやDBに書き込まれるんだけど、「管理対象になった」時点でアプリ全体で使えるデータになるのでここではあんまり気にしない。ちなみに、以前はNSManagedObjectのプロパティをいじるのに毎回valueForKeyやsetValue_forKeyを呼び出してたみたいなんだけど、RubyCocoaの改良でラッパオブジェクトを作るようにして、NSManagedObjectをまるでRubyのオブジェクトのように扱えるようになったらしい。軸がぶれてない、素敵*2。この辺がARっぽいとこ。続いて既にあるデータの取得。NSFetchRequestを用意。RDBMSにSELECTクエリを発行するみたいな感じと言えばいいかな。SELECT文のFROMを指定するのに相当すると理解。SELECT文のWHERE句相当、かな。error)これで「screenNameがrucotanであるUserのリスト」を取得できる。NSFetchRequestとかNSPredicateってのが要はDBハンドラにプリペアードクエリを渡すのと手順は大して変わらないので、日頃DBを使うアプリに慣れてると違和感ないですね。注意点としては、executeFetchRequestの返り値はOSX::NSCFArrayなので、users.empty?とかusers.firstとかやると「そんなメッセージ、わたしが受け付けるとでも思ってるの!?この愚民は言葉もまともに話(ry」と怒られてしまう。Rubyで使うときは最初にto_aしておいた方が楽かも。これだけだとRubyのARやPerlのClass::DBIに慣れきってる身としてはかったるくてしょうがないんだけど、Xcode上のモデリングツールで受信要求テンプレートというのを作ることができて、それを使うとNSFetchRequestの生成が大分楽になる。error)ちなみに、Xcode上で受信要求テンプレートを作る際には述語ビルダというのが使えて、複雑なリクエストでもiTunesやMailのスマートフォルダを作る感覚で述語を生成できてしまうので非常に簡単。いや、まだ使ったことないの。キーバリューコーディングに、ついても書こうと思ったんだけど、そろそろ長くなってきたのでまたの機会に。仮名のRuchettaについてRubyの「る」とCocoaの「こ」がつくものがいいなあと考えて真っ先に浮んだのが「ルッコラ」だったんだけど、rucolaって開発環境があるのね、RubyCocoaの。ルッコラを意味するイタリア語の「Ruchetta」にしてみた(安易)。r(uby)とc(ocoa)とt(witter)が入ったし、「ついった」と「るけった」で語感的にも悪くないかなと思ったんだけどどうだろう。みんなでいじれるようになったら名前も新しく考えてもらってもいいかな。先を越されたこれを書いてる最中に夏ライオン(OSXのtwitterクライアント)のαリリースのお知らせが...。参考にさせてもらおう。夏ライオン見易くてなかなか良かった。自分でtwitterクライアント作ってる最中なのに当面夏ライオンユーザになりそうな予感。アプリ終了時に保存されるのは確かなんだけど、それがどこから何を呼び出してるのか実はわかってない。(4)大分放置してましたけど思い出したかのように続き。いや実際忘れてたのだけども。(3)spceコマンドのラッパを書く前回は自分のリソース内の*_spec.rbを読み込んで自分のmainバンドルのクラスをテストする、というRubyCocoaアプリを作ったのだけど、specを走らせるためだけに毎回そんなものを作るのは面倒くさすぎる。実際やってることはSpec::Runner::CommandLineにspecファイルを渡してるだけなので、ローダブルバンドルを引き数に取ってspecを走らせる、というspecコマンドのラッパを用意する。true)見ての通り、バンドルをロードして*_spec.rbを抜き出し、それらのパスをコマンドライン引数に付け加えてSpecのランナーに渡すだけ。バンドルは最初の一個以外は全部無視する設定になってるけど、俺が想定してる使用方法で扱うバンドルは一個だけなのでとりあえずこれで十分。必要であれば全部受けつけてもいいけど。拡張子が.bundleのファイル以外の引数は全てspecのランナーに渡るので、適当な名前付けてパスの通ったとこに配置しておくとspecコマンドの代わりに使える。-fとか-cとか-sとかも問題なく使えたりする。使用方法で、こいつを実際にどう使うかというと、例えばXcodeを使っているならこんな感じ。$BUILD_DIR/$CONFIGURATION/$EXECUTABLE_NAME.bundleそのターゲットにObjective-Cのクラスとspecファイルを入れる(その際specファイルは必ず末尾に「_spec.rb」を付ける必要がある)これで、このターゲットをビルドすると自動的にspecを実行してくれるようになるという噂。いや、ちゃんとなりました。スペックが全て通ると何事もなくビルド完了するけど、スペックが通らないとビルドが失敗しビルド結果画面にspecコマンドの結果が出る。ビルドターゲットの依存関係でアプリターゲットがspecターゲットに依存するようにしておくと、specが全て通らない限りアプリがビルドできなくなるのでいい感じ。注意点いくつかまず当然のことながらRubyCocoaがインストールされてないと動かない。Leopardだと最初から/System/Library/Frameworks/RubyCocoa.frameworkがあるんだけど、それはもともと入ってるruby(/usr/bin/ruby)からしか使えない。普段から/usr/bin/rubyを使ってる人は別に問題ないけど、それ以外*1を使ってる場合、そのRuby用に再度RubyCocoaを入れるか、/usr/bin/rubyの方でRSpecを入れるかしておく必要がある。あと、RSpecの最新版だとspecの実行結果をsuccessとfailedの他にpendingにすることができるけど、pendingはsuccessと同じ扱いになってビルド成功してしまう。実行結果はビルドログに吐きだされてるのでそれを見ることはできるけども。その他とりあえず結果表示をどうにかしたい。Growlに通知投げたりしたら面白いかなぁ。