Избегать AppleScript через Ruby: rb-appscript или rubyosa?

Привет, коллеги по Mac, рубинисты и ненавистники AppleScript,

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

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

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

4 ответа

Решение

Квот кч:

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

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

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

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

...

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

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

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

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" всегда будет ссылкой на форму "end" of ', как это делает сценарий 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 слов на этой неделе, так что это всего лишь небольшое расслабление.)

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам