Избегать AppleScript через Ruby: rb-appscript или rubyosa? - PullRequest
16 голосов
/ 21 августа 2009

Здравствуйте, коллеги по Mac Mac и ненавистники AppleScript,

Для тех из вас, кто имеет опыт работы как с rubyosa, так и с rb-appscript, я хотел бы услышать плюсы и минусы каждого из них, который вы решили придерживаться, и какой вы бы порекомендовали -AppleScript здравый рубиновый старый таймер. Кроме того, есть ли другие варианты, которые я пропустил?

Кроме того, приветствуются также любые советы, касающиеся части AppleScript уравнения (например, просмотр словарей и т. Д.).

Просмотр некоторых примеров кода также очень помогает.

Ответы [ 4 ]

46 голосов
/ 22 августа 2009

квот кч:

Это хорошо, но теперь мне интересно как скриптовый мост сравнивается с AppleScript. Я думаю, у меня будет немного чтение, чтобы сделать.

SB не поддерживает некоторые функции, имеющиеся в AppleScript. Например, следующий скрипт перемещает все файлы с рабочего стола в папку «Документы»:

tell application "Finder"
   move every file of desktop to folder "Documents" of home
end tell

В SB класс SBElementArray строго ограничивает вашу возможность применять одну команду к нескольким объектам, поэтому вам придется либо прибегнуть к низкоуровневому API, либо получить список отдельных ссылок на файлы и переместить их по одной за раз. :

require 'osx/cocoa'; include OSX
require_framework 'ScriptingBridge'

finder = SBApplication.applicationWithBundleIdentifier('com.apple.finder')
destination = finder.home.folders.objectWithName('Documents')
finder.desktop.files.get.each do |f|
   f.moveTo_replacing_positionedAt_routingSuppressed(destination, nil, nil, nil)
end

В rb-appscript вы бы использовали тот же подход, что и AppleScript:

require 'appscript'; include Appscript

app("Finder").desktop.files.move(:to => app.home.folders["Documents"])

...

SB запутывает механизм событий Apple гораздо сильнее, чем AppleScript. AppleScript может быть болезненным, чтобы разобраться, со странным синтаксисом, склонностью к конфликтам ключевых слов и тому подобным, но помимо этого он в значительной степени представляет события Apple как есть. Единственное действительно существенное чудо в AS - это его неявное получение, когда он оценивает буквальную ссылку, которая не отображается в качестве параметра команды. Самым большим грехом AppleScript является то, что его документация лучше не объясняет, как он на самом деле работает, но есть очень хорошая статья Уильяма Кука , которая проливает много света на то, что на самом деле происходит.

SB, с другой стороны, делает все возможное, чтобы притвориться, что это подлинный API Какао с поведением в стиле Какао, так что накладывает большое количество магии. Результатом является что-то внешне привлекательное для разработчиков Какао, но как только эти абстракции начинают протекать - как это делают неизменно - вы полностью погружены в понимание того, что происходит. Например, SBElementArray утверждает, что является массивом - он даже является подклассом NSMutableArray - но когда вы на самом деле пытаетесь использовать его методы массива, половина из них работает, а половина - нет. На самом деле, это совсем не настоящий массив; это обертка вокруг неоцененного спецификатора объекта события Apple, выдуманная, чтобы притвориться, что это NSMutableArray. Поэтому, когда он делает что-то не похожее на массив, вы в значительной степени разбираетесь в понимании причины. И, как упоминалось в # 1, некоторые из этих толстых абстракций затрудняют доступ к стандартным функциям событий Apple под ними.

SB в первую очередь пытается быть хорошим API Какао, а не хорошим API событий Apple, и в итоге тоже не очень хорош.

Appscript, кстати, следует примеру AppleScript и использует противоположный подход: правильно проводите мероприятия Apple, а затем беспокойтесь о приспособлении языка хоста. Вот почему некоторые люди предпочитают RubyOSA над rb-appscript; Хотя appscript - более эффективное решение, если вы исходите из сильно объектно-ориентированного фона, это будет очень странно. Это связано с тем, что в событиях Apple используется парадигма, основанная на запросе RPC-плюс, и любой сценарий сходства, который может потребоваться для ООП, является чисто синтаксическим. Ближайшая аналогия - отправка XQueries через XML-RPC, и к этому нужно привыкнуть.

...

SB, как правило, страдает значительно большим количеством проблем совместимости приложений, чем AppleScript.

Некоторые из этих проблем связаны с тем, что SB навязывает свои собственные идеи о том, как событие Apple IPC должно работать поверх того, как оно фактически работает. Например, SB создает набор [псевдо] прокси-классов, представляющих классы, определенные в словаре; затем он накладывает различные ограничения на то, как вы можете взаимодействовать с этими объектами, основываясь в основном на классических объектно-ориентированных поведенческих правилах.

Например, следующий скрипт получает имена всех подпапок в папке «Документы»:

tell application "Finder"
   get name of every folder of entire contents of folder "Documents" of home
end tell

Если вы попробуете такой же подход в SB:

finder.home.folders.objectWithName('Documents').entireContents.folders.arrayByApplyingSelector(:name)

он доходит до метода #folders, а затем выдает ошибку, потому что тип свойства 'full contents' в словаре Finder объявлен как 'reference'. Поскольку в словаре не определен «ссылочный» класс с элементами «папка», SB не позволяет вам создать этот конкретный запрос (если только вы не захотите перейти к низкоуровневым API и использовать необработанные коды AE). Это совершенно законно в соответствии с правилами событий Apple, но не вписывается в более узкий OO-ориентированный набор правил, наложенный SB.

Другие ошибки вызваны предположениями SB о том, как приложения с поддержкой скриптов будут реализовывать определенные команды и другие функции. Например:

tell application "iTunes"
   make new playlist with properties {name:"test 1"}
end tell

SB не позволяет вам использовать любые ярлыки, предоставляемые iTunes (вы можете опустить ссылку на исходный объект, для которого вы хотите создать плейлист, в этом случае используется основной источник 'Library'), так что давайте напишите это полностью для лучшего сравнения:

tell application "iTunes"
   make new playlist at source "Library" with properties {name:"test"}
end tell

В SB вы бы написали это как:

itunes = SBApplication.applicationWithBundleIdentifier('com.apple.itunes')

playlists = itunes.sources.objectAtIndex(0).playlists()
newplaylist = itunes.classForScriptingClass(:playlist).alloc().initWithProperties({:name => 'test'})
playlists.addObject(newplaylist)

Когда вы запускаете его, он раздражает #addObject. В своей попытке превратить одну команду «make» в многострочное упражнение SB предполагает, что параметр «at» всегда будет ссылкой на конец формы из , то есть как сценарии Cocoa приложения на основе этого делают. Тем не менее, приложения Carbon не имеют единой стандартной структуры для реализации поддержки событий Apple, поэтому они, как правило, отличаются друг от друга в своих требованиях. Например, iTunes ожидает ссылку на объект контейнера, в данном случае «источник» «Библиотека», и ей не нравится, когда SB передает «конец списка воспроизведения источника« Библиотека »'. Именно так много приложений AppleScriptable, но SB игнорирует эту реальность в своем стремлении быть «объектно-ориентированным».

Еще больше проблем возникает, когда словарь приложения не является на 100% точным или исчерпывающим в деталях. Ни форматы aete, ни sdef не позволяют описать, как интерфейс сценариев приложения работает на 100%; некоторые вещи просто должны быть угаданы пользователями или описаны в дополнительной документации - примером тому может служить свойство «всего содержимого» в Finder. Другая информация, например, какие классы объектов могут быть элементами других классов объектов и тип каждого свойства, на самом деле никогда не используется самим AppleScript - она ​​существует исключительно в качестве пользовательской документации. Поскольку AppleScript не полагается на эту информацию, при тестировании поддержки сценариев приложения для AppleScript будут пропущены любые ошибки, поскольку, несмотря на это, скрипты работают очень хорошо. SB действительно использует эту информацию, поэтому любые опечатки приведут к отсутствующим или сломанным функциям, которые необходимо обойти, снова опустившись до низкоуровневых API.

Appscript, кстати, тоже не на 100% «AppleScript-совместимый», но он действительно намного ближе. Ранние версии appscript также пытались навязать Apple различные события OO, такие как применение объектной модели, определяемой словарем, но после года столкновения с несовместимостью приложений я собрал весь этот «умный» код и потратил следующие несколько лет на попытки черный ящик обратный инжиниринг внутренних махинаций AppleScript и сделать так, чтобы appScript имитировал их как можно ближе. «Если вы не можете победить их (что вы не можете), присоединяйтесь к ним», другими словами. И там, где appscript сталкивается с проблемой совместимости, обычно есть обходные пути, включая переключение внутренних настроек совместимости, экспорт терминологии приложения в модуль, ручное исправление и использование этого вместо этого или переход к низкоуровневому необработанному AE-коду. API-интерфейсы.

...

FWIW, я также должен подключить несколько связанных с этим вкусностей приложений.

Во-первых, инструменты ASDictionary и ASTranslate на сайте приложений являются вашими друзьями. ASDictionary экспортирует словари приложений в формате HTML в стиле appscript, а также включает встроенный метод #help в rb-appscript; отлично подходит для интерактивной разработки в IRB. ASTranslate примет команду AppleScript и (при наличии ошибок) вернет эквивалентную команду в синтаксисе приложения.

Во-вторых, исходный дистрибутив rb-appscript содержит как документацию, так и примеры сценариев. Если вы устанавливаете гем appscript, не забудьте также взять zip-дистрибутив для этих ресурсов.

В-третьих, Мэтт Нойбург написал книгу о rb-appscript . Прочтите его, если вы думаете об использовании rb-appscript. И прочитайте статью доктора Кука, независимо от того, что вы в итоге решите.

...

В любом случае, надеюсь, это поможет. (О, и я прошу прощения за длину, но я только что написал около 25000 слов на этой неделе, так что это всего лишь небольшое расслабление.)

p.s. Нед, твой блестящий доллар на почте. ;)

5 голосов
/ 21 августа 2009

Я не пробовал RubyOSA, но у меня большой успех с rb-appscript . Это отлично сработало для меня и намного приятнее, чем работа с AppleScript напрямую.

Вы видели эту тему, сравнивающую два ? У этого есть хороший подробный ответ, отмечающий различия.

3 голосов
/ 21 августа 2009

Apple включает поддержку сценариев для совместимых с Какао языков через платформу, называемую «Мост сценариев». Я использую это через RubyCocoa / MacRuby для своих скриптовых нужд. Он входит в комплект поставки, поэтому очень удобен.

require 'osx/cocoa'
require_framework 'ScriptingBridge'
iTunes = SBApplication.applicationWithBundleIdentifier 'com.apple.iTunes'
puts iTunes.selection.name

Единственное серьезное раздражение, которое я обнаружил в Мосте сценариев, это то, что вы должны использовать идентификаторы пакетов, а не имена, но в любом случае для меня это не составляет особой проблемы. Он также включен только в 10.5, поэтому, если вам нужна поддержка Panther или Tiger, вам понадобится один из других.

Из двух других, rb-appscript все еще активно разрабатывается, в то время как RubyOSA была фактически заморожена пару лет назад, поэтому я бы, вероятно, выбрал первое. Поскольку Ruby 2, MacRuby и другие новые реализации вызывают изменения в языке, rb-appscript, скорее всего, будет работать в будущем. В остальном они очень похожи. По сути, я отношусь к rb-appscript как к новой версии RubyOSA, хотя это технически неверно.

2 голосов
/ 05 декабря 2009

Краткий ответ: rb-appscript.

Поскольку в Scripting Bridge все выглядит беспорядочно, а RubyOSA больше не поддерживается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...