AppleScript для абсолютных новичков

Дата публикации:18.07.2012
Twitter Facebook Vkontakte

Глава 14. Обработчики всего

AppleScript по природе англоподобный язык, и это помогает сделать сценарий легким в чтении и написании. Мы видели также, что часть ответственности за легкость восприятия сценариев лежит и на вас. Например, это видно, когда вы даете переменной описательное имя, и обеспечиваете ваш сценарий полезными комментариями. AppleScript поможет сохранить читаемость ваших сценариев при помощи "обработчиков" (handlers, также распространено название "подпрограммы"). Предположим, что у вас есть некоторый набор операторов, который встречается несколько раз в вашем сценарии. Если в нем вдруг окажется ошибка, вам придется исправлять каждый из них. AppleScript предлагает возможность группировать такие операторы и давать этой группе имя. Если вы вызовите этот набор по имени, то он будет выполнен .

Здесь показано, как определить обработчик [1].

on warning()
display dialog "Don't do that!" buttons {"OK"} default button "OK"	[1]
end warning

Чтобы его использовать, ваш сценарий должен вызвать обработчик, вот так [2].

warning()	[2]

Не имеет значения где определен обработчик в сценарии до или после вызова обработчика.

Обработчик в сценарии [1] совсем негибкий. Было бы хорошо, если бы могли сказать обработчику какой текст показывать. Угадайте, для чего был разработан этот обработчик [3].

on warning(textToDisplay)
display dialog textToDisplay buttons {"OK"} default button "OK"	[3]
end warning
warning("Don't do that!") warning("Go fishing!")

В операторе [3.1] переменная "textToDisplay" принимает значение передаваемое с вызовом обработчика (в операторах [3.4] и [3.5], каждое из которых содержит значение заключенное в скобки, и это значение передается обработчику). Когда сценарий [3] будет выполнятся, будут показаны последовательно два диалоговых окна.

Вместо указания данных, когда вызывается обработчик, вы можете использовать переменную [4].

on warning(textToDisplay)
display dialog textToDisplay buttons {"OK"} default button "OK"	[4]
end warning
set someText to some item of {"Don't do that!", "Go fishing!"}
warning(someText)

Обратите внимание, что имя переменной используемой, когда вызывается обработчик [4.5], отличается от имени в определении обработчика [4.1]. Теперь вам не нужно знать (искать) имя переменной используемое обработчиком. Конечно, вам надо знать какой тип данных ожидает обработчик.

Вы можете не только передавать информацию обработчику, но и он также может возвращать информацию.

on circleArea(radius)
set area to pi * (radius ^ 2)	[5]
end circleArea
set areaCalculated to circleArea(3)

Обработчик "circleArea()" выполняет вычисление pi*3^2 и автоматически возвращает результат. Автоматическое возвращение результата следует за последним выполняемым оператором обработчика, как будто бы используется команда "get". Чтобы гарантировать, что будет возвращен нужный вам результат, даже если он получен где-то среди серии операторов [6.3], используйте ключевое слово "return" [6].

on older(a)
if a > 30 then
return "older"
end if	[6]
return "not older"
end older
set theAge to older(73)

Если оператор сравнения [6.2] истинный, результат возвращает оператор [6.3], хоть он и не самый последний в обработчике.

Вы не ограничены передачей одной единственной переменной [7.7] обработчику.

on largest(a, b)
if a > b then return a
end if	[7]
return b
end largest
set theLargest to largest(5, 3)

Этот сценарий возвращает большее из двух значений. Обратите внимание, что в операторе [7.1] две переменные обеспечивают доступ к значениям. Соответственно, вызывая обработчик, необходимо передать две переменные [7.7]. В реальных сценариях, по крайней мере одно из этих значений будет передано в виде переменной.

Также можно возвращать более чем одно значение. Для этого нужно возвратить данные как список [8.4].

on circleCalculations(radius)
set area to pi * (radius ^ 2)
set circumference to 2 * pi * radius
return {area, circumference}	[8]
set testVar to 3 end circleCalculations
set circleProperties to circleCalculations(10)

Сценарий выше возвращает список содержащий оба значения: площадь и длину окружности, по заданному радиусу.

Написав сценарий как серию обработчиков и нескольких операторов, которые будут составлять тело вашего сценария, можно сохранить много времени и нервов благодаря одному важному свойству обработчиков. Здесь я задам вам вопрос (на который я сам для себя уже ответил): что если сценарий использует имя переменной, которое уже присутствует для других целей в обработчике? Не волнуйтесь, они не перепутаются. Для доказательства этого, выполним следующий сценарий [9].

set x to 5
on example()
set a to 5 * x	[9]
end example
set y to example()

Вы получите следующую ошибку: Внутри обработчика, переменная x не определена. Если вы хотите, чтобы значение x [9.1] было известно внутри обработчика, вы должны передать её, как продемонстрировано в сценарии [4] .

И наоборот, изменение переменной внутри обработчика не имеет эффекта вне обработчика. Вот доказательство [10].

set x to 5
on example()
set x to 6	[10]
end example
example()
get x

В поле результата видно, что x равно 5. Так что, взаимодействия между сценарием и обработчиком нет, за исключением значений определенным образом передаваемых обработчику и возвращаемых обработчиком. Я должен сказать, что есть еще способ, как сделать переменную "x" оператора [9.1] или [10.1] функциональной в обработчике без передачи ее. Однако, это делает сценарий более трудным для чтения и отладки. Но это также дает большое преимущество обработчикам, о котором рассказано в следующем параграфе.

Если вам интересно узнать, как создать переменную, которая действительна внутри и снаружи обработчика, здесь показано как это сделать: поставьте перед именем переменной ключевое слово "global" (глобально). Рекомендуется сделать это в первой строке(ах) вашего сценария, так вам легче будет найти переменные, которые ведут себя как глобальные.

global x
set x to 5
on example()
set x to 6
end example

example()
get x

Теперь в поле результатов показано, что x равна 6. Из вышесказанного следует, что переменные по умолчанию являются локальными .

Пока я не могу сказать, что мне нравится определять переменные глобально, по причинам объясняемым выше, но есть один тип глобальных переменных, который очень удобен. Они имеют другое название "property" (свойство).

property x : 1
on example()
set x to x + 1
end example

example()
get x

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

Отдельно от описанных выше важных преимуществ (читаемость и т.д.), есть еще одно дополнительное большое преимущество - это то, что вы можете повторно использовать обработчики в других сценариях, которые вы создаете. Поскольку обработчик был использован и протестирован для одного сценария, вы можете быть точно уверены, что он будет работать и в других сценариях. Это сократит время при разработке новых сценариев. Не думайте, что вы сможете скопировать операторы, которые выполнены не в форме обработчика, из одного сценария в другой так же легко. Вы должны будете пройти весь сценарий, чтобы вычислить что надо скопировать, на это уходит много времени. В дополнение, вы рискуете скопировать операторы неполностью и/или операторы, которые будут неверно работать в новом сценарии. Поверьте мне, лучше использовать обработчики.

Замечательно, теперь вы можете ощутить всю эффективность повторного использования обработчиков в других сценариях. Но что если вдруг вы найдете ошибку в обработчике или подумаете о последующем расширении его возможностей? Вы должны будете изменить все сценарии. В AppleScript есть решение этой проблемы - это команда "load script". Все что вы должны сделать:

  1. сохранить один или более обработчиков как скомпилированный сценарии (compiled script);
  2. включить в сценарий оператор нужного обработчика.
set aVariableName to (load script "path here")

Чтобы использовать обработчик компилированного сценария, вы должны использовать блок обращения.

tell aVariableName
handlerName()
end tell

У обработчиков есть одна специфическая особенность, если вы используете блок обращения, без дополнительного указания обработчик окажется неопределенным внутри блока обращения. Если запустить сценарий [11],

on showProgress()
display dialog "Job done!"
end showProgress [11]

tell application "Finder"
empty the trash
showProgress()
end tell

то будет показана такая ошибка:

>...<

Этого легко избежать. Просто укажите, что обработчик принадлежит самому сценарию [12.7].

on showProgress()
display dialog "Job done!"
end showProgress [12]

tell application "Finder"
empty the trash
showProgress() of me
end tell

(AppleScript пытается отправить команду "showProgress()" непосредственно программе "Finder", который о ней ничего не знает, а знает о ней только сценарий. Существует также синоним my - "my showProgress()". - прим. ред.)

Это обязательно только для обработчиков, не для переменных [13], как видно на примере ниже.

set x to 4
tell application "Finder"
set x to 5	[13]
end tell
get x

Результат будет равен 5.

Дополнительная информация

  1. Полный вариант книги (rtf/7z)-- электронная книга с сохранением иллюстраций, форматирования, изменений в цвете шрифта.


Распространение материалов сайта означает, что распространитель принял условия лицензионного соглашения.
Идея и реализация: © Владимир Довыденков и Анатолий Камынин,  2004-2019