AppleScript — это совсем не страшно

Вы еще не используете AppleScript? Не знаете, что это такое? Считаете, будто Вам это ни к чему? Или, быть может, память о школьных уроках информатики вызывает у Вас приступ аллергии при одном упоминании слова «программа»? Значит, Вы правильно сделали, открыв эту статью.

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

Что такое AppleScript

Нередко при работе с той или иной программой нам приходится по многу раз выполнять одинаковые действия: нажимать на одни и те же клавиши, выбирать одну и ту же команду из меню, вводить одни и те же значения в диалоговых окнах… Вот тут-то на помощь и приходит AppleScript. Описываем последовательность наших операций в виде программы-«скрипта», запускаем и — спокойно пьем кофе, изредка поглядывая, не закончилась ли обработка последнего, три тысячи семьсот восемьдесят девятого файла. Нечто подобное существует в виде BAT-файлов DOS или скриптов для оболочек (shell) UNIX. Но у AppleScript есть важное преимущество: этот язык «понимают» как Finder, так и большое число прикладных программ, и скрипт может обращаться поочередно к ним всем.

Язык, которым мы будем пользоваться (он тоже называется AppleScript), очень близок к обычному английскому языку{сноска: на самом деле, так будет, только если у нас используется «английский диалект»}. Например, скрипт может выглядеть вот так:

tell application "Finder"
       make new folder at desktop with properties {name:"Моя!", label index:2}
end tell

Думаю, все поняли, что он сделает. Но чтобы научиться писать свои собственные скрипты, придется разобраться с некоторыми понятиями.

Объекты, свойства, события…

AppleScript — язык объектно-ориентированный. То есть все, что «существует» в вашем компьютере, он считает объектами (objects). Объект может состоять из других объектов, быть включен в другой объект, относиться к другому объекту. Например, Finder — это объект. У него есть «подчиненные» объекты — папки, файлы, окна. В редакторе Tex-Edit имеется объект текст, состоящий из слов, строк, абзацев и т. п. Знать, как соотносятся объекты (их иерархию) очень важно, поскольку команда передается «по цепочке». Действует этакая «вертикаль власти»: мы отдаем приказ Finder’у, он — папке, та — вложенной в нее папке и так далее, пока не дойдет до нужного файла. И «рапорт об исполнении» опять-таки пойдет по той же цепочке — в обратную сторону.

Однотипные объекты (например, все папки) образуют класс (class). Каждый объект обладает некоторым набором свойств (properties), отличающим его от другого. Например, у каждого файла есть имя, метка, тип, дата создания, версия и еще более десятка характеристик. Часть из них скрипт может менять, некоторые — только прочесть.

Один класс (так называемый «потомок») может наследовать свойства другого класса («предка»). Например, и у папок, и у файлов есть общий предок — элемент (item).

Теперь рассмотрим наш пример, немного дополнив его:

-- любой текст, записанный после «двух минусов»,
-- считается комментарием;
-- на него компьютер не обращает внимания
tell application "Finder"
-- словом tell начинается группа команд,
-- относящихся к одному объекту
  make new folder at desktop with properties {name:"Моя!", label index:2}
end tell -- а так завершается группа команд
tell application "Finder" to tell item "Моя!"
  open
  set its name to "Только для меня"
end tell

Мы сперва приказываем программе Finder создать новый объект класса «папка», расположенный на Столе. Часть свойств задано в команде (имя папки и ее цветная метка), остальные будут назначены компьютером по умолчанию. Затем говорим Finder'у, чтоб он скомандовал своей папке (так и только так: «вассал моего вассала — не мой вассал») открыться и сменить имя.

Но пора бы от теоретических рассуждений перейти к чему-то более осязаемому. Самое время запустить Script Editor.

Редактор скриптов

Для работы с AppleScript создано несколько программ, среди которых есть весьма совершенные средства разработки. Впоследствии Вы, вероятно, обзаведетесь одним из них. Но для первоначального знакомства нам вполне хватит редактора, входящего в состав MacOS.

Окно Script Editor разделено на две части: в верхней записывается комментарий (он выводится на экран перед исполнением скрипта), а в нижней — программа. Попробуем набрать наш пример (без моих комментариев, конечно, можно обойтись). Затем щелкнем кнопку «Check syntax». Если Вы допустили какую-либо ошибку, появится окно с пояснением. Но, скорее всего, все будет нормально — и после небольшой паузы текст несколько изменит свой вид. Каким шрифтом при этом будут выделены разные элементы скрипта, можно настроить, воспользовавшись командой «AppleScript Formatting» меню «Edit». Теперь можно нажать кнопку «Run». Сработало?

Написанный скрипт можно сохранить по-разному: либо только исходный текст (Text), либо уже скомпилированный скрипт (Compiled Script) — готовый к исполнению редактором скриптов или некоторыми другими программами, наконец — в виде самостоятельной{сноска: конечно, не совсем — без установленного AppleScript она ничего не сделает} программы-апплета (Application). Можно сделать скрипт «только для исполнения» (Run-only). Только не забудьте в этом случае сохранить — для себя — и оригинальный файл. Иначе добраться до его исходного текста не смогут не только конкуренты, жаждущие нарушить ваши авторские права, но и Вы сами.

Словари, словари, словари…

«Ну, хорошо,»- вероятно, думаете, Вы, -«редактором пользоваться проще простого, прочесть готовые скрипты — тоже не сложно. Но писать-то их как? Откуда взять все эти классы, команды, свойства?» Ответ прост: нужно посмотреть в словаре. Каждая, поддерживающая работу с AppleScript, программа, а также ScriptingAddition (о «дополнениях» разговор еще впереди) содержит краткое описание всех своих объектов и распознаваемых команд. Посмотреть этот словарь можно непосредственно из редактора скриптов — выбрав «Open Dictionary» из меню «File» либо натащив нужную программу на картинку редактора.

Программы Макинтоша могут поддерживать AppleScript на трех разных уровнях.

Scriptable — программа может выполнять команды, описанные в виде скрипта.

Recordable — возможна запись команд, выполняемых в программе. Создадим новый скрипт, запускаем запись (кнопкой «Record»), выполняем, например, в Finder вручную необходимые действия, останавливаем запись («Stop»). Вот и все. Таким образом очень удобно делать заготовки скриптов.

Attachable — скрипт может выполняться непосредственно из программы, будучи «присоединенным» к меню или какому-либо объекту в окне. Примеры таких программ: AppleWorks, Tex-Edit, FileMaker Pro.

Откроем, например, словарь программы Finder.

Слева Вы видите список всех определенных в программе «терминов». Обратите внимание: часть из них набрана курсивом. Это — объекты. Все остальные — команды. Щелкнув на нужное слово, можно прочесть краткую справку.

Что, например, можно узнать про «Container»? Во-первых, мы видим: «Сlass container: An item that contains other items». То есть это — некий элемент, содержащий другие элементы. А если просмотреть описания нескольких следующих классов, станет ясно, что «контейнер» — понятие, включающее в себя и диски, и папки, и Стол (Desktop), и Корзину (Trash). Он обладает общими свойствами этих, во многом схожих, объектов. И в «родословном древе» — иерархии классов — является их предком.

Читаем дальше. «Plural form: containers». Форма множественного числа? Мы разве грамматику английского языка изучаем? И да, и нет. Я ведь уже упоминал, что AppleScript максимально приближен к естественному языку. И если мы хотим обработать все объекты данного класса, то записать это, как и полагается в английском языке, можно либо «every container», либо «containers».

Как Вы уже знаете, объект может содержать в себе другие объекты. Какие именно и чем отличаются друг от друга, описано в следующем разделе словаря — «Элементы» (Elements). Контейнер, как видите, может содержать объекты полутора десятков различных классов, например, другие контейнеры, папки, файлы документов и программ и т. д. А указать конкретный элемент какого-либо класса можно либо именем (by name), либо порядковым номером (by numeric index).

Ну, и наконец, последний раздел — «Свойства» (Properties). Тут мы, во-первых, видим, что класс «Контейнер» — наследник класса «Элемент» (<Inheritance> item [r/o]), то есть обладает всеми его свойствами. Но есть у этого класса и несколько своих собственных. Обратите внимание: часть из них помечена «[r/o]» (read only — только для чтения), эти свойства поменять командой AppleScript невозможно.

Теперь посмотрим, как описаны в словаре команды. Для примера возьмем уже знакомую Вам по примерам скриптов «Make» (создать). В верхней части страницы — назначение команды (создать новый элемент). Затем — как она записывается (синтаксис) и какие имеет параметры. Заметьте: некоторые параметры заключены в квадратные скобки. Так в словаре обозначают необязательные параметры. Составляя скрипт, мы можем без них обойтись, если же будем использовать, никакие скобки ставить не нужно. Завершает справку по команде указание ее результата (Result). В нашем примере им будет «ссылка» (reference) на созданный объект.

Ну, вот. Вы уже можете попробовать написать какой-нибудь простой скрипт. Итак…

О, создатель!

Думаю, Вы знаете, что каждый файл на Макинтоше обладает двумя признаками — типом и кодом создателя, позволяющими Finder'у решить, как с этим файлом обращаться. Не секрет и то, что нередко — например, после передачи через Интернет — эти атрибуты теряются. Конечно, есть немало программ, умеющих их изменять. Но давайте попытаемся сделать свою собственную утилиту, пользуясь только тем, что уже заложено в MacOS.

Начнем с простейшего варианта. Пусть нам нужно назначить файлу letter.txt, находящемуся на Столе, назначить тип «TEXT» и код создателя «ttxt» (ПростоТекст).

Выбираем в словаре программы Finder объект file. Находим нужные нам свойства: file type и creator type. Для изменения значения того или иного свойства используется команда «set» (установить). Стало быть весь скрипт должен выглядеть примерно так:

tell application "Finder" to tell file "letter.txt"
  set its file type to "TEXT"
  set its creator type to "ttxt"
end tell 

Или вот так:

tell application "Finder"
  set file type of file "letter.txt" to "TEXT"
  set creator type of file "letter.txt" to "ttxt"
end tell

Таким образом, как видите, можно либо приказать файлу поменять свои (its) свойства{сноска: в данном примере слово «its» можно опустить, т. к. назначение команды однозначно определено и без него}, либо — программе Finder поменять свойства подчиненного объекта.

Я не зря задал условие, что файл находится на рабочем столе. В ином случае нам потребовалась более длинная «цепочка» подчиненных объектов (что-то вроде «tell application "Finder" to tell disk "Macintosh HD" to tell folder "lesson" to tell file "letter.txt"»). Или же — для второго варианта скрипта — указание полного пути: «file "Macintosh HD:lesson:letter.txt"» (Напомню: путь в MacOS записывается через двоеточия).

Что ж, скрипт написан. Он работает. Но… пользы от него, прямо скажем, никакой — ведь для каждого следующего файла нужно изменять текст самого скрипта. Ничего себе, упростили работу! Надо бы нашу программу усовершенствовать. Научим ее спрашивать пользователя, какой файл обрабатывать. Открываем словарь Finder'а, смотрим… Вот те на! Ничего подходящего. Неужто Apple допустила такую промашку? Вовсе нет…

«А у Вас нет такого же, но с перламутровыми пуговицами?»

Открытая архитектура скриптов (OSA — Open Script Architecture) позволяет обзавестись практически любым необходимым элементом языка. Конечно, если кто-то позаботился написать «дополнение» (Scripting Addition или OSAX), описывающее такой объект и соответствующие команды. Размещаются эти дополнения в папке Scripting Additions, находящейся в System Folder (раньше — в Extensions). Использовать же их может любой скрипт, независимо от того, какой программой он в данный момент командует.

Откроем словарь Standard Additions (чтоб быстро попасть в папку Scripting Additions, в диалоге Open Dictionary предусмотрена специальная кнопка). Вот и она — команда «choose file» (выбрать файл). Результатом ее работы будет ссылка на файл, выбранный человеком в стандартном диалоге Open. Эту ссылку мы сохраним в переменной, которую назовем, к примеру, MyFile.


Для тех, кто забыл школьные уроки информатики как страшный сон. Переменная — это место в памяти компьютера, где хранятся какие-либо данные. Этакий «волшебный ящик» с «табличкой»-именем. Лежащие там данные можно «вынимать» столько раз, сколько потребуется. Но вот стоит только положить что-то новое — и старое значение навсегда исчезнет.

Наш скрипт примет вот такой вид:

 tell application "Finder"
    set MyFile to choose file
    set file type of MyFile to "TEXT"
    set creator type of MyFile to "ttxt"
 end tell
   

Вполне работоспособная программка. Но нельзя ли сделать ее более удобной? Зачем отдельно запускать скрипт, потом выбирать в диалоге имя файла — не лучше ли использовать метод Drag'n'Drop? Все в наших силах!

Пишем Droplet

Итак, что мы хотим получить, и как этого добиться.

  1. Программа должна работать независимо от редактора скриптов. С этим все ясно, мы уже знаем, что для этого ее нужно сохранить как апплет.
  2. Цель работы скрипта — изменение свойств заданного файла. Эта часть у нас уже готова.
  3. Обрабатываться должен файл, «натащенный» на картинку скрипта. Вот тут и начинается самое интересное. С «живущими» в нашем компьютере объектами постоянно происходят разные события. Например файл может быть перемещен, скопирован или открыт. Программа — запуститься, выполнять какие-либо команды или не делать ничего, наконец — завершиться. Чтобы объект «знал», как ему реагировать на то или иное событие, нужна специальная подпрограмма — «обработчик» (handler). Когда на апплет «бросают» файлы, папки или диски, Finder передает ему сообщение-команду «Open» и список «брошенных» объектов. Вот для этого-то события нам и придется написать обработчик.

В простейшем случае он будет выглядеть вот так:

on open FileList -- словом «on» начинается обработчик события
-- сперва скрипт работает сам, не затрагивая никаких программ
  set MyFile to item 1 of FileList
  tell application "Finder" -- теперь командуем Finder'ом
        set file type of MyFile to "TEXT"
        set creator type of MyFile to "ttxt"
  end tell
end open -- не забываем указать, что обработчик закончился

Как видите, обрабатывается первый элемент из переданного при запуске скрипта списка{сноска: Для временного хранения списка мы использовали переменную FileList. Называть переменные можно любыми сочетаниями латинских букв, но желательно так, чтоб по имени можно было понять, что же эта переменная обозначает.}. А остальные? На них наша программа просто не обращает внимания. Не трудно догадаться, что следующим шагом по пути к совершенству будет обработка сразу целой кучи файлов.

Раз, раз, еще раз…

До сих пор все команды наших скриптов выполнялись поочередно в том порядке, как записаны. Теперь же нам нужно повторить одни и те же действия несколько раз подряд. Придется организовать особую структуру — цикл. В AppleScript есть для этого разнообразные управляющие команды. Можно повторить действия наперед заданное число раз, либо выполнять их пока соблюдается некоторое условие. Но такими циклами располагает практически любой язык программирования. В нашей же задаче идеально подойдет другой — «повторить для каждого элемента списка». С ним скрипт примет следующий вид:

on open FileList
  repeat with MyFile in FileList -- так записывают начало цикла
        tell application "Finder"
              set file type of MyFile to "TEXT"
              set creator type of MyFile to "ttxt"
        end tell
  end repeat -- конец управляющей структуры обязательно отмечаем
end open

Чего еще не хватает нашей программе, чтоб стать вполне профессиональной? А не хватает ей «защиты от дурака». Ведь «бросить» на картинку скрипта можно и папки, и ярлыки, а работать он должен только с обычными файлами.

Кого хочешь, выбирай

Стало быть, перебирая элементы списка, нужно определять, чем каждый из них является. Только если попался обычный файл — менять его свойства. Выбрать, делать или не делать какие-либо операции, позволяет еще одна управляющая конструкция — условный оператор If. Определить, не является ли объект папкой или ярлыком, можно, получив информацию о нем командой «info for» из Standard Additions. Результатом ее будет объект класса «file information». Вот его-то свойства — «папка?» (folder) и «ярлык?» (alias) — мы и будем проверять. Поскольку нам необходимо, чтоб элемент не был папкой И не был ярлыком, два условия свяжем логической операцией «and» (когда достаточно выполнения какого-либо одного из условий — ИЛИ первого, ИЛИ второго — пользуются связкой «or»). В общем, в результате наших рассуждений получился вот такой скрипт:

on open FileList
   repeat with MyFile in FileList
        set theInfo to info for MyFile
        if (folder of theInfo is false) and ¬
              (alias of theInfo is false) then
              tell application "Finder"
                    set file type of MyFile to "TEXT"
                    set creator type of MyFile to "ttxt"
              end tell
        end if
  end repeat
end open

Не забываем, что сохранить его нужно как приложение (application). Ну, вот и все. Наша первая программа готова.

Обратите внимание, что все условия в операторе If должны быть записаны в одну строчку. Чтобы сделать текст программы более удобным для чтения, бывает полезно «сложить» длинную строку, как сделано в этом примере. Для этого нужно нажать комбинацию клавиш «Option-Return». В тексте появится символ продолжения — «¬».

Конечно, за это небольшое занятие я смог только немного познакомить Вас с самыми простыми приемами работы с AppleScript. Но, думаю, Вы убедились, что в этом нет ничего сложного. Пробуйте! Я же надеюсь продолжить эту тему в следующих статьях.


[Предыдущая][Содержание][Следующая]
[Новости][Макинтош][Информатика и ИТ][Об авторе]
Hosted by uCoz