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に、actionSelectorをact:に指定しておけば、ちゃんとactが呼ばれます。
疑問
- OSX.require_framework とか使わないで、QSActionProviderとかのQS frameworkが使えてるのはなぜ?
- hisaさんは、この方法だとCPU usageが高くなると懸念されているのですが、僕のところではいまひとつ高くなってるように見えません。why?
まとめ
RubyCocoaで、Quicsilverプラグインを書く方法をまとめました。
これで、あとはRubyのクラスとInfo.plistを書くだけでどんどんプラグインが書けますね。みんながんばれ!
あと、自分でもイマイチだなーと思うことでも、何かしら書いて晒すことが大事なんだなと。そんで改善していければOKなんだ。
hisaさん、ありがとうございました。