Я пишу OS X Service с MacRuby. Это подчеркивает выделенный текст. В основном это работает, но… ну, вот и все:
#!/usr/local/bin/macruby
# encoding: UTF-8
framework 'Foundation'
framework 'AppKit'
class KCUpcase
def upcase(pasteboard, userData: s_userdata, error: s_error)
incoming_string = pasteboard.stringForType "public.utf8-plain-text"
outgoing_string = incoming_string.upcase
pasteboard.clearContents
pasteboard.setString(outgoing_string, forType: "public.utf8-plain-text")
end
end
NSLog "Starting…"
NSRegisterServicesProvider(KCUpcase.new, "Upcase")
NSLog "Registered…"
NSRunLoop.currentRunLoop\
.acceptInputForMode(NSDefaultRunLoopMode,
beforeDate:NSDate.dateWithTimeIntervalSinceNow(10.0))
NSLog "Done."
Это просто инструмент Foundation, а не часть приложения.
Теперь, видите строку NSRunLoop…
? Это на самом деле не работает. Программа выходит сразу. Я полагаю, цикл запускается один раз, а затем завершается. Anyhoo, факт в том, что он определенно не ждет 10 секунд для ввода. Итак, вот что я сделал вместо этого:
NSRunLoop.currentRunLoop.runUntilDate NSDate.dateWithTimeIntervalSinceNow(60.0)
И это работает, но, естественно, программа задерживается на 60-е годы, и это клудж. Так что я реализовал все это в Objective C (включая KCUpcase, который не показан). И ... это работает. С ручным управлением памятью. Как только я переключаюсь на GC (-fobjc-gc-only
), он сразу же завершает работу, как и версия MacRuby.
#import <Foundation/Foundation.h>
#import "KCUpcase.h"
int main (int argc, const char * argv[]) {
NSLog(@"Starting…");
NSRegisterServicesProvider([[KCUpcase alloc] init], @"KCUpcase");
NSLog(@"Registered…");
[[NSRunLoop currentRunLoop]
acceptInputForMode:NSDefaultRunLoopMode
beforeDate:[NSDate dateWithTimeIntervalSinceNow:10.0]];
NSLog(@"Done.");
return 0;
}
Но, увы, исправить это легко: поскольку это инструмент Foundation (а не NSApplication), кажется, мне нужно вручную запустить GC, вызвав objc_startCollectorThread
. Здесь:
#import <objc/objc-auto.h>
// ...
NSLog(@"Starting…");
objc_startCollectorThread();
NSRegisterServicesProvider([[KCUpcase alloc] init], @"KCUpcase");
// ...
Хорошо, но что тогда с MacRuby? Давайте добавим это в смесь:
#import <MacRuby/MacRuby.h>
// ...
NSLog(@"Starting…");
objc_startCollectorThread(); // This magic stops working once we add MacRuby
[[MacRuby sharedRuntime] evaluateString: @"$stderr.puts 'hi from macruby'"];
NSRegisterServicesProvider([[KCUpcase alloc] init], @"KCUpcase");
// ...
И опять же, это не ожидание в цикле. И, опять же, использование runUntilDate:
kludge вместо acceptInputForMode:beforeDate:
работает:
NSLog(@"Starting…");
[[MacRuby sharedRuntime] evaluateString: @"$stderr.puts 'hi from macruby'"];
NSRegisterServicesProvider([[KCUpcase alloc] init], @"KCUpcase");
NSLog(@"Registered…");
// Hmmm…
[[NSRunLoop currentRunLoop]
runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]];
NSLog(@"Done.");
return 0;
Итак, я предполагаю, что упускаю что-то ужасно очевидное. Пожалуйста, просветите меня.
И, между прочим, полная версия проекта MacRuby доступна здесь ( загрузка ) с задачей Rake, которая будет собирать и устанавливать ее в ~/Library/Services
. Затем вам нужно включить его флажок в разделе «Службы» на панели настроек клавиатуры (один раз).
(или git clone git://gist.github.com/537075.git
)
В сторону : Интересно, что я попытался вызвать NSLog
внутри строки MacRuby, и она подняла NoMethodError
. Что дает?