Tag Archive for 'mac'

Grand Central Dispatch をためす (1)

Snow Leopard がでましたね!

OpenCL と Grand Central Dispatch がおもしろそうなので、そのへんのことを書いていくシリーズです。まずは Grand Central Dispatch について、手がかりのない状態からかるく使ってみるまで。

0. Grand Central Dispatch について

前に少し書いたように、Snow Leopard から入る並列実行基盤ですね。

1. Xcode でドキュメント探し

Xcode のドキュメントビューア (えらくインターフェイスがかわった) から、 Grand Central とか Dispatch とかをキーワードにして検索すると、それらしいタイトルがひっかかります。しかし、内容をみることはまだできないみたい。 ADC の上級メンバーならよいのでしょうが、ヒラ会員の我々は無理なの?

2. カンをつかう

mdfind dispatch とかしてみるわけです。すると

/usr/share/man/man3/dispatch.3

とかひっかかる。これはあやしい。 というわけで man 3 dispatchman 3 dispatch_async としていくと、概念を紹介するためのサンプルコードが書かれている man ページにあたります。ビンゴですね。

3. 書いてみる

6-9 行がミソですね。 global queue に、ブロックないの処理を非同期で実行するようつっこんでるわけです。

4. 実行してみる

% ./a.out
hoge
... (寝てる)
%

ちゃんと非同期で実行されてます。

5. 確かめてみる

gdb であそんでみましょう。

% gdb a.out
(gdb) b 7           # ブロック内で break
(gdb run
Starting program: /Users/mootoh/gcd_sandbox
[Switching to process 10433]

Breakpoint 1, __main_block_invoke_1 (.block_descriptor=0x100001080) at gcd_sandbox.c:7
7               printf("hoge\n");

とまりました。 switching to process とかでてますね。スレッド切り替えがおこったのでしょう。

(gdb) bt
#0  __main_block_invoke_1 (.block_descriptor=0x100001080) at gcd_sandbox.c:7
#1  0x00007fff85bc2dc7 in _dispatch_call_block_and_release ()
#2  0x00007fff85ba1341 in _dispatch_worker_thread2 ()
#3  0x00007fff85ba0c80 in _pthread_wqthread ()
#4  0x00007fff85ba0b1d in start_wqthread ()

wqthread とな。 Worker Queue thread とかかな? スレッド全体をみてみましょう。

(gdb) info threads
* 2 port# 0x417 __main_block_invoke_1 (.block_descriptor=0x100001080) at gcd_sandbox.c:7
  1 port# 0x903 0x00007fff85bc1ace in __semwait_signal ()
(gdb) thread 1
(gdb) bt
#0  0x00007fff85bc1ace in __semwait_signal ()
#1  0x00007fff85bc195d in nanosleep ()
#2  0x00007fff85c0f320 in sleep ()
#3  0x0000000100000e94 in main (argc=1, argv=0x7fff5fbfe9b0) at gcd_sandbox.c:10

ちゃんと元スレッドがいますね。

6. その他

そういえば、 gcc に何のオプションも指定することなく、ふつうに Grand Central Dispatch のブロック構文が使えていました。また、特になにかライブラリをリンクすることもなく、ただ gcc -g gcd_sandbox.c これだけでビルドできて並列実行できるバイナリが生成されますね。うむむ。

7. まとめ

ADC ヒラ会員なので、まとまったドキュメントとして man 3 dispatch 周りだけをたよりに Grand Central Dispatch を覗いてみました。ブロック構文がちゃんと使えることをまず確認し、 gdb からもちゃんとマルチスレッドの動作が見える、というところまでを追いました。

あと気になるのは、ハイレベル API がどういうものなのか、というところです。 Cocoa 的なのがあるとすれば、 .framework にまとまってるだろうと思うのですけれど、それらしきものはまだ見つけられていません。

次回はもう少し掘り下げてみたいとおもいます。それまでにドキュメント手に入るようにならないかなぁ…

20009-09-02 21:13 JST 追記

その2 を書きました。

Bonjour

iPhone アプリをつくってて、 Bonjour をつかえばいろいろと楽しいことができるんじゃない? と調べていました。ここまでのところをシェア。

Bonjour というのは、 DNS サーバがなくても、同じネットワーク内にいるコンピュータを見つけあうことができる技術。 Zero Configuration とか Rendezvous とか言われてたりもした。

準備

遊びでつかうなら、 service type = _wwdcpic あたりでローカルで遊ぶといいんじゃないかな。

本気でつかうなら、dns-sd にサービスの登録をする。 サービス名、説明、責任者といった情報をつけてメールすれば、そのうち受理されたりする。

Cocoa API

いいところ:

  • 使いやすく抽象化されてる
  • Mac, iPhone どちらでも同じように使える!

ちゃんと RubyCocoa でも使えたよ!

NSNetService

サーバ側。サービスを提供していることをアピールし、クライアントから接続されてくるのを待つ。

ながれ:

  • initWithDomain_type_name_port
  • setDelegate
  • publish

ここの type で指定するのを、 dns-sd に登録しておくということ。 クライアントとのやりとりは delegate のコールバックに通知される。 接続されたあとの処理は、ふつうのネットワークプログラムとおなじ。

NSNetServiceBrowser

クライアント側。サーバをてきとうに探し出して、接続する。

ながれ:

  • init
  • setDelegate
  • searchForServicesOfType

みつかったあとのサーバとのやりとりは、 delegate のコールバックに通知される。

Sample code

/Developer/Examples//Foundation/PictureSharing

このコードを読むと、だいたい把握できる。

あと、自分で書いたコードが github:remoteshortcuts にあります。 Mac with RubyCocoa, iPhone とごちゃまぜなかんじがたのしいかと。

つまづきポイント

  • NSNetService は、 stop を送られたあとにもう一度 publish で起動しようとしてもダメ (しぬ)
  • delegate を設定する前にメッセージを送っても意味なし

まとめ

想像以上にかんたんに使えました。 Cocoa フレームワークはすばらしい。 iPhone アプリどうしで小さなネットワークをつくって遊ぶようなときにさくっと使うと楽しそうです。勉強会とか。

SafariでMigemoを使えるようにしようとした

SIMBLプラグインをつくる習作として、Safariのページ内検索にMigemoをつかえるようにできないか試行錯誤してみました。 分かったことは、SIMBLプラグインとしてつくるのは難しそう、ということでした。

作戦

Migemoの出力は正規表現です。

例: takai → (タカイ|タカイ|隆一|多階層|他界|高[市石鼾泉井]|たかい|takai|takai)

対して、Safariのページ内検索は1つのキーワードに対する全文検索です。 つまり、探すべきキーワードが1つから複数に変わるということです。これは大きな差。

ならば、元のコードでキーワードを渡して検索している関数を、キーワードの個数ぶんだけ繰り返し呼べば所望の機能が実現できそうだ、と考えました。

どこに手を入れるか

Safariの文字列検索を追う で書いていたように、WebView::searchFor にブレークポイントをはり、デバッガでステップ実行して挙動を調べました。

コードを書き変える

まず、元の searachFor メソッドを _safari_searchFor メソッドに変名してとっておき、 この_safari_searchFor メソッドをMigemoの正規表現から得られる文字列の数だけ呼び出す、という戦略を考えます。 うまくいけば、SIMBLプラグインとして実装する際に Method Swizzling として実現できますね。

ためしに、与えられたキーワードと google の2つで検索するようにしてみました。

Index: mac/WebView/WebViewPrivate.h
===================================================================
--- mac/WebView/WebViewPrivate.h        (revision 32849)
+++ mac/WebView/WebViewPrivate.h        (working copy)
@@ -106,6 +106,9 @@
  */
 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection;
 
+- (BOOL)_safari_searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection;
+
+
 - (void)setMainFrameDocumentReady:(BOOL)mainFrameDocumentReady;
 - (void)setTabKeyCyclesThroughElements:(BOOL)cyclesElements;
Index: mac/WebView/WebView.mm
===================================================================
--- mac/WebView/WebView.mm      (revision 32849)
+++ mac/WebView/WebView.mm      (working copy)
@@ -3002,6 +3002,14 @@
 
 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection
 {
+  BOOL ret1 = [self _safari_searchFor:@"google" direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:startInSelection];
+  BOOL ret2 = [self _safari_searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:startInSelection];
+
+  return ret1 and ret2;
+}
+
+- (BOOL)_safari_searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection
+{
  if (_private->closed)
    return NO;
 
@@ -3247,24 +3255,27 @@
 
 - (NSUInteger)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight limit:(NSUInteger)limit
 {
-    WebFrame *frame = [self mainFrame];+    NSString *strs[2] = {@"google", string};
     unsigned matchCount = 0;
-    do {
-        id <WebDocumentView> view = [[frame frameView] documentView];
-        if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) {
-            [(NSView <WebMultipleTextMatches>*)view  setMarkedTextMatchesAreHighlighted:highlight];
-            ASSERT(limit == 0 || matchCount < limit);
-            matchCount += [(NSView <WebMultipleTextMatches>*)view markAllMatchesForText:string caseSensitive:caseFlag limit:limit == 0 ? 0 : limit - matchCount];
 
-            // Stop looking if we've reached the limit. A limit of 0 means no limit.
-            if (limit > 0 && matchCount >= limit)
-                break;
-        }
-        
-        frame = incrementFrame(frame, YES, NO);
-    } while (frame);
-
+    for (int i(0); i<2; i++) {
+        WebFrame *frame = [self mainFrame];
+        do {
+            id <WebDocumentView> view = [[frame frameView] documentView];
+            if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) {
+                [(NSView <WebMultipleTextMatches>*)view  setMarkedTextMatchesAreHighlighted:highlight];
+                ASSERT(limit == 0 || matchCount < limit);
+                matchCount += [(NSView <WebMultipleTextMatches>*)view markAllMatchesForText:strs[i] caseSensitive:caseFlag limit:limit == 0 ? 0 : limit - matchCount];
+                
+                // Stop looking if we've reached the limit. A limit of 0 means no limit.
+                if (limit > 0 && matchCount >= limit)
+                    break;
+            }
+            
+            frame = incrementFrame(frame, YES, NO);
+        } while (frame);
+    }
     return matchCount;
 }

じっさいに、マッチしたキーワードをハイライト表示させているのは markAllMatchesForText というメソッドのようだったので、 こちらにも複数キーワード対応するためのハックを仕込んでおきます。

実行結果

result

複数キーワードがハイライト表示されました。やりましたね :) ただし、「次の候補へ」のようにして、次のマッチ文字列に飛ぼうとしても、同じキーワード間でしかジャンプできませんでした。 ><

原因と対策

そもそも、キーワードにマッチした元のテキストやマッチした結果はどこに保存されているのか。 これを調べていくと WebCore の中に入っていくことになります。 WebCoreはKHTML由来のコードで、C++で書かれているライブラリです。 となると、Objective-C みたいに実行時に柔軟なメソッド差し替えはできなくなってしまいます。 今回はSIMBLプラグインの習作が目的だったので、深追いはここまで。

本気でやるならば、C/Migemoと鬼車をWebCoreにリンクして、マッチしたテキストの範囲などを複数キーワードに対応させればよいでしょう。

まとめ

あと少しだったんだけどなあ…

手駒

  • Migemoの実装には、C/Migemoをつかいます。
  • Migemoの出力は正規表現なので、鬼車のCocoa版であるOgreKitをつかいます。
  • Safariをハックするには、WebKitをデバッグビルドするのが便利です。
  • Cocoaアプリを拡張するには、SIMBLプラグインをつくるのが定石です。

夏ライオンにメッセージフィルタリングをつけるハック

@akrさんがつくっている、夏ライオンというTwitterクライアントに、表示されるメッセージを特定の条件でフィルタリングするハックをしてみました。

何ができるか

特定のユーザのメッセージだけを表示したり、

ある言葉が含まれるメッセージだけを表示したりできます。

キモ

  • どこから手をつけるか
  • NSPredicate をつかう

長くなるので、続きは以下で。

Continue reading ‘夏ライオンにメッセージフィルタリングをつけるハック’

Xacti DMX-HD1000

Xacti DMX-HD1000 (黒) を買いました。 Full HD (1080i, 1920×1080 60fps) の H.264/AVC でSDHCカードに撮影でき、重さが280gしかないという優れものです。 ここではMacといっしょに使うという観点で、二日使った感想を書いてみます。

環境:

  • MacBook (2GHz Core 2 Duo, 2GB RAM)
  • Mac OS X 10.5.2
  • iLife ‘06

単なるMP4ファイル

ひとつの撮影は、単にひとつのMP4ファイルとしてSDHCカードに保存されています。 カードリーダーをMacにつなげば、ふつうのファイルコピーだけど映像の取り込みが完了する、というのは、これまで Firewire でDVカメラから映像を取り込んでいたぼくにとっては革命的な手軽さでした。

テープというシーケンシャルアクセスから、ランダムアクセスできるSDカードにメディアが変わったことのインパクトはすごいものです (他の例: FDD→HDD、VHS→HDDレコーダ、などなど)。 他にもまだ、シーケンシャルアクセスでしか使えないものがあれば、そこにはイノベーションのチャンスがある、ということですね。

QuickTimeでの再生

このMP4ファイルはQuickTime Playerで簡単に再生できることもポイントですね。 ただし、Full HD のMP4ファイルはそのままでは再生することができなくて、avc1DecoderというものをインストールするとOKでした。

Full HD のMP4ファイルの再生はさすがにCPUパワーを酷使しますが、再生時にだいたい25〜29fpsは出ていました。ギリギリ再生が追いついている、というところですね。

iMovie で編集

Full HDのMP4ファイルをそのままiMovieに放り込むと、音は聞こえど画像は出ない、という状態になります。価格.comにある情報 に従い、先頭フレームだけをQuickTimeでカットし (先頭でCmd-XすればOK) 、参照ムービーとして保存したものをiMovieでimportすると、ちゃんと編集できました。

iMovieのプロジェクトは、新規作成するときに HD-1080i-30 の形式を選んでおくと、HDの編集ができます。これに最初気づかずにはまりました。

Webカムとして使う

Xacti DMX-1000は、Webカムとしても使えると説明書にあります。 ただし、Windowsでしか使えないよと書かれており、ほんとかいよとMacにUSBでつないでXactiの設定をしてみると、ふつうにQuickTimeの録画ソースとしてXactiを使うことができました。

まとめ

買う前は、ほんとにMacでもちゃんと使えるのか不安でしたが、ちゃんと使えました! 実売で6万円を切っているし、Full HD なビデオカメラが欲しいMacユーザに、とってもおすすめです。


SanDisk UltraII SDHC 8GB SDSDRH-8192-903
サンディスク (2007-10-05)
売り上げランキング: 1509

TimeCapsuleをマウントする

TimeCapsule - Mac mini

TimeCapsuleを買いました。1TBです。 我が家の3台のMacを、TimeMachineで自動バックアップさせてます。 自動バックアップがいかにストレスを減らしてくれるものかは、体験してみないと分からないものですね。

で、いくら3台あるとはいえ、バックアップだけに1TBも使いきりません。 そこで、ふつうのNASとして使おうとAFPでマウントしてみます。 TimeCapsuleはFinderに見えているので、ふつうにマウントできます。

そこでファイルをちょこちょことコピーしてみたところ、パーミッションが変わってしまうことに気づきました。

-rw-r--r--   1 moto  www       10240  3  5 11:28 test.tar
  ↓
-rwxrwxrwx   1 moto  staff       10240  3  5 11:28 test.tar

みたいになります。File modeが0777、グループがマウントしているユーザのグループに、といった具合。

ふつうに使うぶんには困らないのですが、UNIX的な使い方をしている人は注意したほうがいいですね。 回避方法をご存知の方はぜひコメントください。

QSTwitter 1.4

QuicksilverからTwitterに投稿するプラグイン、QSTwitterを1.4にアップデートしました。 ダウンロードはこちら。 まだ若干バギーです :) が、 つかってみてくださいね。

変更点

Triggerで一発ポスト !

後述のTrigger設定をすることにより、ショートカット一発でTwitterにポストできるようにしました。

これまで:

  • QS起動
  • テキストモードに移行 (ピリオド入力)
  • テキスト入力
  • タブキーでActionに移動
  • postと入力 (ここを抜かして、’Large Type’になるミスが多発していました)
  • ENTER でポスト

1.4:

  • Triggerのショートカット入力
  • テキスト入力
  • ENTER でポスト !

ステップ数で2倍、体感速度およびストレスでさらに倍程度速くなりました。

Trigger のセットアップ

カタログをつくったあと、図のような手順を踏みます。ショートカットキーはお好きなものを。ターゲットのとこをブランクにするのがコツかと。

参考: わかばマークのMacの備忘録 : Quicksilver/ Proxy Objects について

スクリーンショット

注意事項

1.3と同様です。

中のつくりについて

QSTwitterというダミーfollowingユーザをつくり、ここにreplyするとpublic timelineに発言するようなフェイクをつくることでTriggerを実現しました。

コード

CodeRepos : TwitterPlugin

以前のバージョン

  • 1.3 : 2008.02.22
  • 1.2 : 2008.01.23
  • 1.1 : 2007.12.22

関連エントリ

QSTwitter 1.3

QuicksilverからTwitterに投稿するプラグイン、QSTwitterを1.3にアップデートしました。 ダウンロードはこちら。 若干バギーです :)

変更点

Friendの補完

自分がfollowしているひと (= Friend) をカタログに保持し、 Quicksilverから補完入力できるようにしました。 アイコンが表示されるのがキュート。

Reply Action

補完入力したFriendに対して、reply Action でメッセージを送れるようにしました。 自動的に、@だれそれがメッセージの先頭につきます。

HTTP プロキシ

環境変数に、http_proxyが設定されている場合に、そのプロキシサーバを使うようにしました。

Action名の変更

これまでは、TwitterというActionでメッセージを送っていましたが、 postというActionに名前を変えました。

スクリーンショット

スクリーンキャスト

百聞は一見にしかずということで。

注意事項

  • Mac OS X 10.5.2 でしか確認していません。Leopardが必須です。RubyCocoaがインストールされているTigerでも、ひょっとしたらビルドできるかも。
  • JSONのRubyライブラリが必要です。sudo gem install jsonなどとしてインストールしてください。
  • インストールした直後、Quicksilverが固まります。これは、Friendすべてをダウンロードしてカタログ化しているためです。
  • 初回のカタログが生成されたあと、Quicksilverがクラッシュしたり暴走したりします。Quicksilverを再起動すると、ちゃんと動くようです。 (調査中)

中のつくりについて

これまではObjective-Cで書いていたのですが、RubyCocoaで書き直しました。 メリットとしては、以下のようなものがあります。

  • JSONが簡単に扱える
  • HTTP POST via プロキシができる (NSURLConnectionではなかなかうまくいかない)
  • デバッグがラク ( /reload と postすると、Rubyスクリプトが再読み込みされるようになってる)

また、コードを見てもらえると分かるのですが、カタログ化のためにダウンロードしたFriendのJSONを、 Marshal.dumpでPluginがインストールされた場所にキャッシュしています。 なんという手抜き。

コード

CodeRepos : TwitterPlugin

以前のバージョン

  • 1.2 : 2008.01.23
  • 1.1 : 2007.12.22

関連エントリ

LeopardでのQuartzComposerカスタムプラグインづくり

Ruby会議2008CFPとして、RubyCocoaでインタラクティブにMacのプラグインをつくるよ、みたいなものを書いて出してみました。 出してから、そういえばLeopardになってからQuartzComposerで遊んでないなあと気づき、ちょっと触ってみたらえらく変わっていたので、今日調べたことをカスタムプラグインをつくるという観点でメモっときます。

カスタムプラグインがオフィシャルに

最大の変更点はこれです。 Appleの丁寧なドキュメント Introduction to Quartz Composer Custom Patch Programming Guide を読めば、たちまちつくれるようになるのではないかと。サンプルも充実してて、/Developer/Examples/Quartz\ Composer/Plugins/にごろごろ転がってます。 これまで、kineme.net:Xcode Template for Custom Quartz Composer Patches を使い、非公開のAPIでプログラミングしていたのに対して大きな進歩です。

Port指定にはpropertyをつかう

Objective-C 2.0で導入された、propertyという機能をつかって入出力Portの指定をコードでやるようになっています。 これまでは、インスタンス変数名の先頭にinput/outputがあれば、それがPortになっていました。

Portの増減が動的にできる

RubyCocoaでpropertyを使う方法を知らないのでどうしようかなあと思ってたのですが、 addinputPortWithTypeとかaddOutputPortWithTypeというメソッドを使えば動的にPortが加えられます。

注意すべきことは、これらのメソッドはプラグインのexecuteメソッドに入れてはいけないことです (例外があがってQuartzComposerが止まってしまいます)。んじゃどうするかということで、ExampleのCommandLineToolFreeFrameHostを調べてみると、どうやらQuartzComposerのインスペクタから受け取るイベントのハンドラで、これらのメソッドを呼ぶようにしています。なるほど。

インストール場所が変わっている

これまでは、/Library/Graphics/Patch にプラグインを置くのが流儀だったのですが、Leopardからは/Library/Graphics/Quartz\ Composer\ Plug-Ins/ になりました(~/Library以下でもOK)。


カスタムプラグインをつくるという点から、Leopardになって気づいたことをまとめました。次はいよいよ、RubyCocoaでカスタムプラグインづくりです。

関連エントリ

もっとRubyCocoaでQuicksilverプラグインを書く

RubyCocoaを使ってQuicksilverプラグインを書く の続編です。 前回書いたあと、hisaさんからアドバイスをもらい、RubyCocoaプラグインを書くことができるようになりました。

ポイントは以下の2つ。

  • NSPrincipalClass
  • RubyActionClass < OSX::QSActionProvider

コードは、CodeReposのものをupdateしておきました。 hisaさんコードがたくさん入っていますが、煮るなり焼くなり好きにせよとのことなので、前回と同じ修正BSDライセンスとします。

NSPrincipalClass

Quicksilver プラグインに限らず、Cocoaで何らかのBundleを書く際には、Info.plistの NSPrincipalClass にクラス名を指定しておくと、そのクラスの +load() メソッドが呼ばれてプラグインが組み込まれるようです。 なので、ここでRBBundleInit()を呼んでRubyCocoaを初期化すると。とてもスマート。 前回はこのことを知らずに、無理矢理なハックをしていたのでした。

RCLoader.m:

ここでは、NSPrincipalClassにRCLoaderというクラスを指定しています。

@implementation RCLoader
 
+ (void)load {
  static bool installed = 0;
 
  if (! installed) {
    if (! RBBundleInit("load_ruby.rb", [self class], self)) {
      installed = true;
    }
  }
}

load_ruby.rb:

そんで、RubyCocoaの初期化の中で、必要な.rbを読み込んでおく、と。

def load_ruby_programs(bundle, logger)
  path = bundle.resourcePath.fileSystemRepresentation
  rbfiles = Dir.entries(path).select {|x| /\.rb\z/ =~ x}
  rbfiles -= [ File.basename(__FILE__) ]
  rbfiles.each do |path|
    require( File.basename(path) )
  end
end
 
OSX.init_for_bundle do |bundle, param, logger|
  load_ruby_programs(bundle, logger)
end

RubyActionClass < OSX::QSActionProvider

前回説明したように、QuicksilverのActionを記述するには、QSActionProviderを継承したクラスでメソッドを用意します。 今回は、RubyのクラスでQSActionProviderを実装します。RubyCocoaのパワーがすごすぎる。

class RubyAction < OSX::QSActionProvider
  def act(arg)
    val = arg.stringValue
    OSX::QSObject.objectWithString('Hello world, ' + val)
  end
end

あとは、このRubyActionクラスを、Info.plistのactionClassに、actionSelectoract:に指定しておけば、ちゃんとactが呼ばれます。

疑問

  • OSX.require_framework とか使わないで、QSActionProviderとかのQS frameworkが使えてるのはなぜ?
  • hisaさんは、この方法だとCPU usageが高くなると懸念されているのですが、僕のところではいまひとつ高くなってるように見えません。why?

まとめ

RubyCocoaで、Quicsilverプラグインを書く方法をまとめました。 これで、あとはRubyのクラスとInfo.plistを書くだけでどんどんプラグインが書けますね。みんながんばれ!

あと、自分でもイマイチだなーと思うことでも、何かしら書いて晒すことが大事なんだなと。そんで改善していければOKなんだ。 hisaさん、ありがとうございました。