Search the Catalog
AppleScript in a Nutshell

AppleScript in a Nutshell

By Bruce W. Perry
June 2001
1-56592-841-5, Order Number: 8415
526 pages, $29.95

Chapter 7
Flow-Control Statements

The flow-control statements in AppleScript orchestrate the "flow" or the order in which the code statements execute in your scripts. Programmers will be familiar with AppleScript's if conditional statements, which are very similar to the syntax of Visual Basic, Perl, and other languages. These statements execute code only if the tested conditions are true. AppleScript handles loops in script code with several variations of the repeat statement, similar to the "for," "foreach," or "for each" statements in other languages. The repeat flow-control construct repeats the execution of code a specified number of times or for each member of a container, such as a list type. Or, it repeats a code phrase a specified number of times:

repeat 100 times...end repeat

You will be pleased to know that AppleScript has more than adequate error-trapping capabilities. This is accomplished by enclosing the statements that may raise errors in a try...end try statement block. In addition, you have already seen dozens of examples of the tell..end tell statement in earlier chapters. These statements specify the objects, usually application objects, that receive the commands or Apple events that your script sends. You specify the targets of different script commands by using these tell statements.

You can nest flow-control statements within other flow-control statements. Most of these statements end, appropriately, with the reserved word end, optionally followed by the statement identifier, such as tell or repeat. An example is:

tell app "Photoshop 5.5"...end tell

The if and tell statements allow "simple" rather than "compound" usage, such as:

if (current date) > date "1/1/2001" then display dialog "Welcome to 2001"

These simple statements appear on one line, they do not contain other code statements, and they do not need to be completed with the end reserved word. This code shows some nested flow-control statements and simple statements:

tell application "Finder"
   set freeMemoryBlock to largest free block
   (* Here's a simple statement; no 'end' is necessary *)
   if freeMemoryBlock < 10000000 then display dialog ¬
   "Memory is getting low" 
   set listOfProcesses to name of processes
   if "BBEdit 5.0" is not in listOfProcesses then (* compound 'if' 
statement *)
      tell application "BBEdit 5.0" to run -- simple 'tell' statement
   end if
end tell

Suffice it to say, flow-control statements are how AppleScript derives much of its power and complexity. You will develop very few scripts that do not use at least one flow-control statement. Table 7-1 lists the statements that this chapter describes.

Table 7-1: Flow-Control Statements

considering

repeat with loop variable

continue

repeat integer times

error

return

exit

tell simple statement

if simple statement

tell compound statement

if compound statement

try

ignoring

using terms from

repeat

with timeout

repeat until

with transaction

repeat while

 

considering [but ignoring] end [considering]

Syntax

Considering case
   "animal" is equal to "AniMal" -- returns false
end considering

Description

Use considering statements to specify the elements that should be considered during string comparisons and communications with other applications. The statements that constitute the comparison are enclosed in the considering...end considering block. This statement block affects how each of its enclosed statements is processed. The considering statement can also alter AppleScript's default behavior for the code that is executed prior to the end of the considering statement (signaled by an end or end considering phrase). For example, if you wanted to compare two strings and take upper- or lowercase characters into account, but ignore any white space in the strings, then you would use the statement: considering case but ignoring white space...end considering. AppleScript's default behavior is to consider elements such as case, white space, and punctuation when it compares strings for equality. The following constants can also be used in the considering statement (Chapter 6, Variables and Constants, discusses AppleScript's constants):

AppleScript considers by default an application's responses to any Apple events that your script sends them. You can use the ignoring statement to ignore responses from an application, as in considering case but ignoring application responses.

There are a few instances when ignoring application responses might make sense, such as when you are sending quit commands to several running processes. If one of the processes responds to the command with an error, then the script ignores its response (as well as any other application response) and thus prevents it from disrupting the execution of the rest of the script. See "ignoring" in this chapter for more details.

Examples

This code shows how to use this statement with a fairly complex string comparison:

tell application "Finder"
   considering case but ignoring punctuation, white space and hyphens
      set theTruth to ("voracious appetite" is equal to "voracious, ¬
      appetite") --returns true
   end considering
end tell

The example tells AppleScript which elements to consider and ignore when executing the string comparison within the considering statement block. Since white space, hyphens, and punctuation should be ignored in the comparison, the two strings turn out the same. Therefore, the theTruth variable is set to true. If you are wondering why you would ever ignore these elements in a string comparison, programs often deal with a lot of junk characters and tokens, such as markup-language elements, which are returned from applications or web pages. The considering statement allows you, in a minimal way, to filter out elements that you do not want to include in string comparisons (unfortunately, you will have to write custom functions or use an HTML-parsing osax to filter out the common < > characters in hypertext markup language [HTML], as AppleScript does not consider them to be "punctuation").

continue

Syntax

On parMethod(int )
   If somethingTrue then
      (* code statements here *)
   else
      continue parMethod(int) -- call parent script's parMethod version
   end if
end parMethod

Description

The continue statement is used to call a parent script's method from a child script. In AppleScript, a child script can inherit properties and methods from a parent script. This topic is covered in Chapter 9, Script Objects and Libraries. The child script specifies its parent (if it has one) by declaring a parent property at the top of the script:

property parent : NameOfScript

The NameOfScript part can be either the name of a script object or an application, such as:

application "Finder"

A child script inherits the methods of a parent; it does not have to define these methods. However, the child script can "override" the parent method(s) by redefining them in the body of the script. Within these redefined methods, it can use the continue statement to call the parent method. The following example constitutes a child script that calls its parent's version of the parMethod function based on the magnitude of the numerical argument passed to the method. The child object handles real numbers and the parent handles integers.

Examples

On parMethod(int )
   If (class of int is real) then
      Return (int * 2)
   Else
      continue parMethod(int) (* it's an integer so call the parent 
      parMethod *)
   end if
end parMethod

error

Syntax

error myErrText number 9000 -- myErrText contains the error description

Description

The error statement allows you to raise an error based on certain script conditions. Why would you ever want to raise an error? You may want to catch an error in a function but handle the error in the part of the code that called the function, higher up in the call chain. So you would use the error statement to pass the error up to the calling function, such as in the following example. This is similar to "throwing" an exception in Java.

Examples

This example uses a getNumber method to get a number from the user, but it does not bother (for the sake of demonstration) to check the entry to ensure that the user has entered a valid number. If the user enters data that is not a number then the statement:

return (theNum as number)

causes an error, because AppleScript cannot coerce non-numeric characters to a number. To be specific, this is AppleScript error number -1700. The getNumber method catches the error and uses an error statement to pass the original error's error message and number back to the calling handler (in this case the script's run handler), which then catches the "re-raised" error and displays a message:

on run
   try
      display dialog "Your number is: " & (getNumber(  ) as text)
   on error errmesg number errn
      display dialog errmesg & return & return & "error number: " & ¬ 
         (errn as text)
   end try
end run
on getNumber(  )
   set theNum to (text returned of (display dialog ¬
   "Please enter a  number:" default answer ""))
   try
      return (theNum as number)
      on error errmesg number errnumber
      error errmesg number errnumber
   end try
end getNumber

The error statement also gives the scripter more control on how program errors are handled. For example, you can catch an error in a script with a try block (see "try" later in this chapter), examine the nature of the error, then re-raise the error with the error statement providing a more lucid error message to the user. This is best illustrated with the following code, which catches an error caused by coercing a non-numeric string to a real data type:

(* use the display-dialog scripting addition to ask the user to enter a number *)
set aNum to the text returned of (display dialog "Enter a number" ¬
default  answer "")
try
   set aNum to aNum as real (* non-numeric string like "10ab" will raise an error *)
on error number errNumber
   set myErrText to "Can't coerce the supplied text to a real: " & ¬
   return & "The AS error number is " & errNumber
   error myErrText number 9000 -- add your own error number
end try

The code first asks the user to enter a number, using the display dialog scripting addition. This produces a dialog box with a text-entry field. If the user enters some text that cannot be coerced to a number, such as 10ab (the included letters ab cause the coercion to fail), the expression:

set aNum to aNum as real

causes the script to raise an error. The try block catches the error, and then processes the statements following the on error code. These statements include:

error myErrText number 9000

which produces an AppleScript error-dialog box and adds the scripter's custom message (stored in the variable myErrText). It also provides a custom error number of 9000. You can create your own groups of error numbers or variables for certain error conditions, which your script can then identify and respond to with more accuracy and clarity than if the scripter only relied on AppleScript's error numbers.

The next two examples illustrate the setup and usage of custom error variables. The first example is a script that contains several user-defined error variables for some common errors that occur in AppleScripts. This script is loaded into the current script using the load script scripting addition (Appendix A, Standard Scripting Additions, discusses scripting additions, or osaxen). The example only contains three constants, but it could define dozens of them to accommodate most or all of the possible script errors that could occur. The constants are set to the actual values that AppleScript assigns to the errors that represent, for example, the failure to coerce data from one type to another (i.e., error number -1700):

set FAILED_COERCION to -1700
 
set MISSING_PARAMETER to -1701
 
set TIMEDOUT_APPLEEVENT to -1712

You can then test for certain errors and, if you discover them, display more informative messages or take some other appropriate action. For example, the script in the following code sets the variable objErrors to the script object defined in the prior example. It then uses the FAILED_COERCION and TIMEDOUT_APPLEEVENT constants from that object to test for these error conditions. In other words, the TIMEDOUT_APPLEEVENT variable contains AppleScript's actual error number for Apple events that time out (-1712), but it is easier to remember if it is stored in a variable with a coherent name. If either of these errors is detected, the error statement is used to produce a dialog box with your own error message:

set objErrors to (load script file "HFSA2gig:nutshell book:demo ¬ scripts:scr_0504")(* this script object contains

the user-defined error variables *)
set userReply to the text returned of (display dialog ¬ "Please enter a number" default answer "") try set aNum to userReply as real (* if the user doesn't provide a number this statement will fail and the try block will catch the error *) on error errM number errNumber if errNumber is equal to (objErrors's FAILED_COERCION) then (* FAILED_COERCION is a property of the script object stored in objError *) error "The number you provided was not a valid integer or real." else if errNumber is equal to (objErrors's TIMEDOUT_APPLEEVENT) then error "For some reason AppleScript timed out." else -- default error message for all other errors set defMessage to "Sorry, AppleScript error number: " & errNumber & ¬ "occurred in the script. Here's
AppleScript's error description: " & errM error defMessage
end if end try

The error statement includes a number of optional parameters. It is important to remember that you supply the values for these parameters (if you want to use them). With try blocks and on error statements, AppleScript itself will fill these parameters with values (see "try" later in this chapter):

The following example demonstrates how to pass the information about an AppleScript error to an error statement. The script intentionally raises an error by using a string instead of a boolean expression in an if statement. Then it passes the error data as a long string to an error statement:

try
   if "not a boolean" then (* this causes an error, caught in the try block *)
      beep 2
   end if
on error errMessage number errNum from errSource partial result ¬ 
errList  to class_constant -- various variables store information about the error
   set bigmessage to "The error is: " & errMessage & return & ¬
   "The number is: " & errNum & return & "The source is: " & errSource
   error bigmessage -- error statement displays dialog box to user
end try

exit [repeat]

Syntax

repeat 2 times
   exit repeat
end repeat

Description

The exit statement causes the flow of script execution to leave the exit statement's repeat loop. The execution then resumes with the script code following the repeat loop. exit can only be used inside of a repeat loop, regardless of the repeat-loop variation. Using exit is the conventional way to exit a repeat loop that has no conditional statement associated with it, as shown in this example. In other words, this form of repeat is an infinite loop:

repeat
   set userReply to the text returned of (display dialog "Want to get ¬
   out of this endless loop?" default answer "")
   if userReply is "yes" then exit repeat
end repeat

This endless loop can also be exited by clicking the Cancel button on the dialog produced by display dialog, which terminates the execution of the script.

if simple statement

Syntax

If theBool is true then exit repeat

Description

AppleScript supports the simple if statement that is similar to Perl's. You can use a statement such as the following:

if (current date) is greater than or equal to date "1/1/2001" then ¬ display dialog "Welcome to 2001"

You do not have to "close" this statement with an end or end if, as you do with more wordy compound statements. You just include the reserved word if followed by a boolean expression (returns true or false), the reserved word then, and whichever statement you would like to execute if the boolean expression returns true. This example has several different versions of the if statement. Since there are two different versions of the same date-test expression, this script will create two of the same dialog boxes:

if (current date) is greater than or equal to date "Saturday, January ¬
1,  2000 12:00:00 AM" then display dialog "Welcome to 2000" (* simple if statement *)
if (current date) is less than date "Saturday, January 1, 2000 12:00:00 ¬ AM" then display dialog "Enjoy end of

1999" -- simple if statement
set yearCount to 0 if (current date) 3 date "Saturday, January 1, 2000 12:00:00 AM" then --compound if statement display dialog "Welcome to 2000" set yearCount to yearCount + 1 else if (current date) ¬ < date "Saturday, January 1, 2000 12:00:00 AM" then display dialog "Enjoy end of 1999" end if

Use a simple if statement if the script only has to execute one line of code in the event that the boolean expression tests true. Otherwise use a compound if statement.

if [then] [else if] [else] end [if]

Syntax

If theBoolean then
   (* code statements *)
else if anotherBool then
   (* code statements *)
else
   (* code statements *)
end if

Description

The compound if statement can be used to test several boolean expressions and only execute subsequent script code if the enclosing expression is true. The syntax of the if compound statement is almost exactly the same as Visual Basic's, JavaScript's, and Perl's, with some minor differences (for example, VB pushes the else and if together to make "elseif"). A plain-English pseudocode translation of this statement would be, "if this happens then run this code; else if that happens then run this code; else (if neither of the first two things happen) then run this default code." You do not have to include any curly-brace characters ({ }) to enclose the conditional script code that the if statement contains. As long as you place different lines of code on separate lines, then the then part of if...then and the if part of end if are optional, as in the following code. The compiler puts the "thens" and "end if" in the right places.

Examples

In the following example, the (current date) date "1/1/2001" is the tested boolean expression. If it's false, then the else statement(s) will execute.

Set yearCount to 0
if (current date)  date "1/1/2001"  -- compiler will fill in 'then'
   display dialog "Welcome to 2001"
   set yearCount to yearCount + 1
else
   display dialog "Enjoy the end of 2000"
end -- 'if' is optional

ignoring [but considering] end [ignoring]

Syntax

ignoring application responses
end ignoring

Description

You can use this statement block to control string comparisons. The ignoring statement is used with application responses to disregard any responses from the apps that receive the script commands:

ignoring application responses...end ignoring

The following AppleScript constants are the parameters to the ignoring statement. They are all considered by default:

Examples

This code shows how to use ignoring...end ignoring. Believe it or not, the code:

"j'u-n,k t?'ext" is equal to "junk text"

returns true, because the enclosing ignoring block tells AppleScript to ignore punctuation and hyphens when making the string comparison:

ignoring punctuation and hyphens but considering case
   return ("j'u-n,k t?'ext" is equal to "junk text") (*returns true because punctuation is ignored in the comparison *)
end ignoring

If you want to ignore more than one constant, just separate them with the and operator:

ignoring punctuation and white space and hyphens and expansion.

You can also use the but considering parameter followed by one of the specified constants (e.g., hyphen, white space) to ignore some elements but consider others:

ignoring punctuation but considering white space

repeat end [repeat]

Syntax

repeat
   if someTrueCondition then exit repeat
end repeat

Description

repeat without any conditional statements associated with it results in an infinite loop. In most cases, you need to use an exit statement to terminate the loop and resume execution with the statement that follows end repeat. This statement begins with repeat on its own line and finishes with an end or an end repeat (the repeat part of end repeat is optional). All of the statements that should execute within the loop appear between the repeat and end repeat lines. You can nest repeat loops within each other.

Examples

This AppleScript shows one repeat loop nested within another. It also illustrates that the exit statement only exits the repeat statement in which exit is contained. So the example actually needs two exit statements to emerge from its repetition purgatory:

repeat -- outer repeat loop
   repeat -- beginning of inner repeat loop
      set userReply to the text returned of ¬
      (display dialog ¬
         "Want to get out of inner endless loop?" default  answer "")
   if userReply is "yes" then exit repeat
   end repeat
   set userReply to the text returned of ¬
   (display dialog "Want to get out of outer endless loop?" default  ¬
   answer "")
   if userReply is "yes" then exit repeat
end repeat

repeat until end [repeat]

Syntax

Repeat until trueBoolean
   (* code statements *)
end repeat

Description

This form of repeat takes the until keyword and a boolean expression, as in: repeat until countVar is true. The statements that are contained within repeat until...end repeat will continue to execute until the boolean conditional expression is true. If the expression following until is true, the repeat loop is terminated and execution resumes with the statement following end repeat. You could also exit this repeat loop using the exit statement (see exit). Note that when repeat until encounters a true value, the loop is immediately ended; its enclosed statements are not executed.

Examples

This AppleScript shows a repeat until statement that also contains an exit statement:

set theCount to 0
repeat until (theCount = 5)
   if theCount = 4 then exit repeat
   set theCount to theCount + 1
   log theCount
end repeat

This code increments a theCount integer variable by one with each cycle through the loop. The code includes a simple if statement that exits the repeat loop once the theCount variable reaches 4. Without the exit statement, the variable would reach 5; the expression: theCount = 5 would return true, and the repeat until loop would terminate. We keep track of the value of theCount with a log theCount statement. This displays all of the theCount values in Script Editor's Event Log window.

repeat while end [repeat]

Syntax

Repeat while trueBoolean
   (* code statements *)
end repeat

Description

repeat while keeps executing its enclosed script code as long as the boolean expression following while is true:

repeat while theTruth is true...end repeat

If the boolean expression that follows while returns false, then the repeat while loop is terminated, and its enclosed script code will not execute anymore. Script execution then resumes after the end repeat part of the repeat while statement. repeat while has the opposite effect of repeat until; it keeps executing as long as some boolean expression is true, whereas repeat until keeps executing until something is true. You can also use exit within repeat while to leave the loop. In general, Repeat loops can contain nested repeat loops, as well as other flow-control statements such as if and tell.

Examples

This code shows how to use repeat while:

set theCount to 0
repeat while (theCount < 5)
   set theCount to theCount + 1
   log theCount
end repeat

The two code lines within this repeat while statement block will continue executing (thus increasing the value of theCount by one) while theCount is less than 5. Each cycle through the loop tests the boolean expression:

theCount < 5

and, as long as this expression returns true, the enclosed code will execute again. The variable theCount actually reaches 5 in the following code. This is because it is eventually incremented to 4, then the:

repeat while (theCount < 5)

executes and, since theCount is still less than 5, the enclosed script code executes once more, increasing the variable's value to 5.

repeat with {loop variable} from {integer} to {integer} [by stepVal] end [repeat]

Syntax

Repeat with loopVar from 1 to 10
   (* code statements *)
end repeat

Description

This form of the repeat loop executes a specified number of times over a range of values. A loop variable keeps track of how far the repeat loop has progressed in cycling over its range of loops. The loop variable increments by the value of stepVal (or one by default if the stepVal variable is not specified) throughout each loop. This makes the repeat with statement much more flexible and powerful than repeat {integer} times. You can take the value of the loop variable and use it in the executing code, as in the following example. Once this repeat with statement reaches the end of its range, as in:

repeat with loopVar from 1 to 10

(10 is the end of the range here), then the repeat loop terminates and code execution resumes with the statement following end repeat. You can also use the exit statement to terminate this loop (see "exit"). repeat with is similar to the famous:

for (i=0; i < rangeVar; i++)

variation of the loop statement that JavaScript, Java, and C++ programmers are very familiar with.

Examples

This AppleScript loops through each character of a word to see if any character is repeated. It uses the loop variable to determine which character in the word to examine. This example also shows how you can specify any of the range values with expressions that return integers, instead of just literal integers:

repeat with loopVar from 2 to (2^2)
   set theString to the text returned of (display dialog ¬
   "Enter a word and I'll tell you which letter, if any, repeats first" ¬
   default answer "")
   set len to (length of theString) (* len is set to the number of characters in string *)
   tell application "BBEdit 5.0"
      repeat with loopVar from 1 to len (* repeat from char 1 to length of string *)
         if loopVar is equal to 1 then set charList to {} (*create a list to hold the examined characters *)
         set tempChar to (character loopVar of theString) (* tempChar is a single character in the string like 'o' *)
         if tempChar is in charList then (* if it's already in the list 
         then it appears more than once in the string *) 
            display dialog  "Your repeating character is " & tempChar
            exit repeat (* exits the repeat loop; finishes executing the 
            script *)
         end if
         set charList to charList & tempChar (* no repeating chars yet so add the current char to the list *)
         if loopVar is equal to len then (* if this is true then we did not find any repeaters *)
            display dialog "You had no repeating characters!"
         end if
      end repeat
   end tell
end repeat

This script uses the BBEdit text editor because this app is good at examining text. The script gets a word from the user using the display dialog scripting addition (Part IV of the book discusses scripting additions). Then it uses a repeat with loop to get each single character in the string and store it in a variable of type list (i.e., charList). This is how the script keeps track of the characters it has already examined. The loopVar of the repeat with statement identifies individual characters of the string with an index reference form, as in character loopVar. If loopVar were 3 then the expression would evaluate to character 3, which is the third character in the string. The code then checks the charList list of characters to see if the currently examined character is already in there. If the character is already in the list then it appears more than once in the string. Then the script tells the user which character repeated and exits the loop:

display dialog "Your repeating character is " & tempChar

This example shows this repeat with loop with a specified step value:

set theString to "Kindly give me every other word."
set allWd to words of theString -- returns list of words
set len to length of allWd
set userMsg to ""
repeat with indx from 1 to len by 2 -- repeat loops over the list by two
   set userMsg to userMsg & return & (item indx of allWd)
end repeat
display dialog "Here's every other word on its own line: " & return & ¬ userMsg

repeat with {loop variable} in {list} end [repeat]

Syntax

Repeat with listVar in myList
   (* code statements *)
end repeat

Description

This variation of the repeat with statement iterates over a list of values, storing the current value in the loop variable. Once the last item in the list has been stored in the loop variable, the statement terminates and code execution resumes after end repeat. If you have to examine a list's contents, this statement is a crucial part of your code. You can also use the exit statement inside this repeat with statement to stop executing code inside the loop. After any call to exit, code execution resumes after the end repeat part. You do not have to declare the loop variable in any way; AppleScript creates this temporary reference variable for you. You can also get the loop variable's value later in the script, after the repeat loop has completed executing. The value will be a reference to the last item in the list:

item 6 of {"Each", "word", "on", "a", "different", "line"}

Using this form of repeat loop, you can get inaccurate results if the script is trying to compare the value of the loop variable with another value (such as a string or integer). Instead, one of our technical reviewers recommends that you use syntax such as:

set booleanVar to ((contents of loopVar) equals 1)" (* note the "contents of" part *)

The value used in the part of the statement following the in reserved word must be a list.

Examples

This code takes each of the items of a list and concatenates them to a string, which is then displayed to the user:

set theString to "Each word on a different line"
set theList to words of theString -- returns a list of words
set displayString to "" -- initialize this string
repeat with wd in theList
   set displayString to displayString & return & wd
end repeat
display dialog displayString
wd as string -- this will return "line"

AppleScript does not destroy the loop variable (wd in the prior example) after the repeat loop is finished. Getting the value of wd in the last example, after the repeat with statement has done its job, returns:

item 6 of {"Each", "word", "on", "a", "different", "line"}

repeat {integer} times end [repeat]

Syntax

Repeat 10 times
   Display dialog contriteStatement
End repeat

Description

This loop statement begins with the reserved word repeat, followed by an integer representing the number of times the loop should cycle, then the reserved word times and an end repeat. (The repeat of end repeat is optional.) You can use this variation of repeat if you do not need the finesse of the two more complex but powerful repeat constructs, such as:

repeat with loopVar in list

Once this loop has executed its enclosed script statements integer number of times, it terminates and the script execution resumes after the end repeat. You can also short-circuit this repeat loop by using the exit or exit repeat statement. This causes the script flow to proceed to after end repeat, regardless of whether the loop has cycled integer number of times.

Examples

The following code does exactly what the last repeat example did; it works with each word in a list, finally displaying each of them on a different line. However, it uses the "repeat {integer} times" variation instead. The example also shows that you can use the return value of an expression for "{integer}" including an integer variable, instead of just a literal integer such as 9:

set theString to "Each word on a different line"
set theList to words of theString
set len to length of theList
set displayString to ""
set counter to 0
repeat len times -- len resolves to the length of the word list
   set counter to counter + 1
   set displayString to displayString & return & (item counter of ¬ 
   theList)
end repeat
display dialog displayString

In this example, the line repeat len times uses the len variable's integer value to specify how many times the repeat loop should execute. len represents the length of the list of words that the code reassembles into another string.

return [return value]

Syntax

Return true

Description

The return statement returns values from functions or subroutines, just as it does in Perl and JavaScript. If you finish a function definition with just return, with no subsequent return value, then the function will return to where it was called in the script without returning an actual value. You can return any value, such as a number, string, boolean, or list:

return true

If you do not use return at all in a function then the return value of the function will be the result of its last statement, if the statement returns a result. (Chapter 9 is devoted to developing functions in AppleScript.)

If you define a function with just return without a value and then try to set a variable to the return value of that function, the script will raise an error.

Make sure not to confuse the return statement with the return predefined variable, which is a return character in a string such as:

set theString to return & "Start a new line"

tell simple statement

Syntax

tell app "SoundJam MP" to run

Description

You use the tell statement to identify the target of an AppleScript command:

tell app "Photoshop 5.5" to run

In this case, run is the Photoshop application's command. The tell simple statement only takes up one line of code and does not need to be completed with an end tell. You use the reserved word tell, followed by a reference to an object, such as the application "Finder," then the reserved word to preceding the actual command that you want to send to the object. tell statements can be nested within each other, such as using a tell simple statement inside a compound tell statement (one that involves several lines of code and finishes with end tell).

Examples

This code tells the Finder to open Photoshop only if a certain amount of memory is available to the computer:

tell application "Finder"
   (* largest free block is converted from bytes to megabytes then rounded off with the round scripting addition *)
   set freeMem to (round (largest free block / 1024 / 1024))
   if freeMem > 50 then (* only open PS if there is a free memory block > 
   50 meg *)
      tell application "Adobe® Photoshop® 5.5" to activate (* tell simple 
      statement *)
   else
      display dialog ¬
"Freemem = " & freeMem & " Not enough memory for gluttonous Photoshop!"
   end if
end tell

This example occurs within a compound tell statement that targets the Finder. If the largest free block property of the Finder (which identifies the largest free block of available RAM on the computer) exceeds 50MB, then Photoshop receives an activate command as part of a tell simple statement.

TIP:   If you are running AppleScript 1.4 or higher, you can create easy-to- remember aliases to invoke your favorite apps with the tell statement. For example, create an alias file for the SoundJam MP application, name this alias "SJ," and then store it in startup disk:System Folder:Scripting Additions. Now, when your AppleScripts include the code: tell app "SJ" the enclosed code statements direct their Apple Events to SoundJam MP. This saves a lot of typing!

tell end [tell]

Syntax

Tell app "SoundJam MP"
   (* code statements *)
end tell

Description

The tell compound statement identifies the target of an AppleScript command or Apple event (as in tell app "Photoshop 5.5") followed by other AppleScript statements and an end tell. The tell compound statement can enclose any number of AppleScript statements, including other tell statements and flow-control structures such as if or repeat. You can identify any object in a tell statement, but unless the object is an application object such as FileMaker Pro or QuarkXPress, it has to be nested within another tell statement targeting the object's parent application. For example, if you want to use a statement such as:

tell window 1 to close

then you would have to first target the application that "owns" the window, as in the following example:

tell application "BBEdit 5.0"
   (* hasChanged will be true or false *)
   set hasChanged to (front window's modified)
   if hasChanged then
      tell front window to close saving yes
   else
      tell front window to close
   end if
end tell

This script first finds out whether the front BBEdit window has been modified, and it stores this boolean value (true or false) in the hasChanged variable. If true, then a tell simple statement sends the front BBEdit window a close command (with a parameter instructing BBEdit to save the changes). If this tell statement was not nested within the tell app "BBEdit"... statement, then AppleScript would not know which application's window the script was talking about, and an error would be raised. You could also write the program without a nested tell statement, as in this code:

tell application "BBEdit 5.0"
   set hasChanged to (front window's modified)
   if hasChanged then
      close front window saving yes  (* send BBEdit the close command
      without another tell statement *)
   else
      close front window
   end if
end tell

TIP:   With a feature that was new to AppleScript 1.4, you can add aliases to applications in the Scripting Additions folder of the System Folder. Give these aliases a short, easy-to-recall name like "fm" for FileMaker Pro, and you no longer have to spell out the app's name in the tell statement. You can just use the syntax tell app "fm"..., and AppleScript will find the application.

You can also use the predefined variables me, my, and it within tell statements. AppleScript assumes that any command such as activate, close, or open within a tell statement should be directed to the application that is identified in the tell statement. The exceptions are:

Examples

The script at the end of this section calls the script's own function inside of a tell statement. It also calls a function defined by a script object. it is an AppleScript reserved word that refers to the default target of Apple events, which is normally identified in a tell statement (Chapter 1, AppleScript: An Introduction, describes Apple events). This script is a little bigger than most included in the chapter, and I apologize to those like me who are partial to the use of only code fragments as examples. But it illustrates an important element of how you work with tell statements--the visibility of commands.

The script first identifies the text editor BBEdit in the compound tell statement, then tells this app to make a new window. The next line sets a firstLine variable to the return value of a function call:

InnerScript's getIntro(  )

Without the reference to the script object InnerScript, AppleScript would assume that the getIntro function was a BBEdit command, because getIntro is called inside of a tell app "BBEdit 5.0" statement. However, the script code indicates that this is the getIntro function of the InnerScript object. The following code would also work:

set firstLine to getIntro(  ) of InnerScript

If you look down to the definition of the InnerScript script object, you see that it defines a function (getIntro) that returns the value of InnerScript's Intro property, which is a string: "I'm the first sentence." A lot is going on in the if statement in the next example:

if (my addLine(firstLine)) then display dialog "Text added ¬
successfully:  " & its name

The script calls its own function (as opposed to a BBEdit command) called addLine. The reserved word my distinguishes this function (addLine) as defined by the script, not BBEdit, so AppleScript looks for the function definition in the script itself, rather than in BBEdit's dictionary. The following phrase would also work:

addLine(firstLine) of me

The function inserts text into a BBEdit document and returns true if successful. The if statement responds to any true return value from the addLine function by displaying a message string that includes its name. It is an AppleScript constant that refers to the default target for commands, which, inside this tell statement, is BBEdit. So its name returns "BBEdit 5.0":

tell application "BBEdit 5.1"
   make new window with properties {name:"Front Win"}
   (* the InnerScript script object is defined beneath this code *)
   set firstLine to InnerScript's getIntro(  )
   (* addLine is the 'outer script's' function, not InnerScript's *)
   if (my addLine(firstLine)) then display dialog ¬
"Text added  successfully: " & its name
end tell
 
(* user-defined function addline(  ) *)
on addLine(txt)
   try
      tell application "BBEdit 5.1" to insert text txt
   on error
      return false
   end try
   return true
end addLine
(* script object definition *)
script InnerScript
   property Intro : "I'm the first sentence."
   on getIntro(  )
      return Intro
   end getIntro
end script

try [on error] [number | from | partial result | to] end [error | try]

Syntax

Try
   (* code statements here *)
   on error errText
   display dialog "An error:" & errText
end try

Description

try represents AppleScript's all-important error-trapping capability. If any of the statements that are enclosed in a try...end try statement block raise an error, then AppleScript catches the error and prevents it from taking down the whole script. After try catches the error (similar to Java's try...catch exception-trapping syntax), the script has the option of adding inside the try block the reserved words on error followed by any code that should execute in response to the error.

TIP:  on error is optional inside of try statements beginning with AppleScript 1.4.

The program will then resume following the end try part of the try block, as though nothing happened. Without a try block, AppleScript's default error behavior is to display an error message in a dialog box then cancel the running script. try only catches one error at a time. By using the on error statement and its numerous parameters, you can uncover all kinds of details about the error, but you do not have to use it. In the OS versions previous to Mac OS 9, Script Editor does not compile a script that includes a try block without an on error statement.

Examples

This example traps any errors caused by invalid data entered by the user, and then goes on its merry way without explicitly responding to any errors. try statements can be used inside and outside of your own subroutines, script objects, and libraries; they can nest other statements such as if, repeat, and tell. In fact, your entire script can run inside of a try statement, and the try block can contain other try statements:

try
   set userReply to the text returned of ¬
      (display dialog "Try your best to enter a number." default answer ¬ 
      "")
   set invalidNum to false
   set userReply to userReply as real
on error
   set invalidNum to true
end try
if invalidNum then
   display dialog "That's the best you can do?!"
else
   display dialog "thanks for entering: " & userReply
end if

This script politely asks the user for a number; it sets the reply to the variable userReply. This variable is then coerced from a string to a real type, which raises an error if userReply is not a valid number. For example, "a10" couldn't be converted to a valid number. AppleScript displays this error and stops running the script if we do not catch it in the try block. If the error is raised, the statements that appear between on error and end try execute. In this case, the script sets a boolean variable invalidNum to true. Remember, the script does not have to use the on error statement part of try in Mac OS 9 or OS X. It can simply use a try block to prevent any errors from crashing the script, then go on blithely executing the rest of the code. The error handler of the try statement contains five variables from which you can obtain information about any errors. The following code shows two of the many ways that you can use try. The first demonstration catches but then skips over any errors that might be raised while it executes its code. The second use of try deploys the on error handler to grab all the data that it can about the error and display it to the user:

tell application "SoundJam? MP"
   try
      activate (* will raise an error if SoundJam isn't on the computer, 
      but the program will just keep going *)
   end try
   try
      set allPlay to playlist windows -- a list of playlists
      repeat with pl in allPlay
         if (name of pl) is "tranceControl" then set mainPlay to pl
      end repeat
      set trackNameList to name of (tracks of mainPlay)
      set trackMsg to ""
      on error errMsg number errNum from objErr partial result errList ¬
      to  errClass 
      (* display the error message, error number, the object that is the 
      source of the error, any partial results, and class information *)
         display dialog errMsg & ": " & errNum & return & "Source of ¬ 
         error   was: " & objErr & return & "Here are any partial ¬ 
         results: " &  errList & return & "If coercion failure it ¬
         involved a coercion to: " & errClass
     return -- exit the program
   end try
   repeat with nam in trackNameList
      set trackMsg to trackMsg & return & nam
   end repeat
   display dialog "The MP3 track names in the main playlist are: " & ¬ 
   return & trackMsg
end tell

In the prior example, if any statements in the second try block raise an error, then the on error handler displays error information using all five parameters of on error. AppleScript gives these parameters a value (e.g., the error description and number) for you if any errors are raised. The values for the partial list and to parameters are empty lists if there are no partial results or coercion problems associated with the error. Here's a rundown of the five optional on error parameters:

using terms from end [using terms from]

Syntax

Tell app "Finder" of machine "eppc://192.168.0.2"
   Using terms from app "Finder"
      Get largest free block
   End using terms from
End tell

Description

This block structure allows the scripter to compile a script using local applications and to have the option to run the script on remote machines using a TCP/IP or AppleTalk network. Chapter 25, File Sharing Control Panel, describes how to use the Mac's powerful new program linking technology to run distributed AppleScripts over TCP/IP networks. using terms from is new to AppleScript 1.4. Similar to the tell block, it takes an application object as a parameter, as in:

using terms from app "Finder"

You use this construct to help avoid the display of the Script Editor dialog box that asks for the location of the target application in a tell block. This dialog box usually displays when the script is first compiled and then whenever the script is executed on a different machine. If you have not encountered this dialog box yet during AppleScript hacking, then you are either lucky or just haven't done very much AppleScripting.

Examples

using terms from is best illustrated with this example, which dynamically targets whatever machine you want, but compiles using terms from the local machine:

set theMachine to "eppc://" & the text returned of ¬
(display dialog "Enter your IP address:" default answer "")
try
   tell application "Finder" of machine theMachine
      using terms from application "Finder"
         set freeMem to (round (largest free block / 1024 / 1024)) as ¬ 
         string
         display dialog freeMem
      end using terms from
   end tell
on error errMsg
   display dialog errMsg
end try

This script targets the Finder on a particular Apple machine (depending on what the script user enters as the machine name or IP address). The script compiles, however, using its local Finder app. If the user enters an invalid or nonexistent IP address, then an error is raised and reported at the end of the try block. When targeting applications over a TCP/IP network, you have to precede the IP address with the protocol "eppc://", which stands for "event program to program communications":

tell application "Finder" of machine "eppc://192.168.0.2"

with timeout [of] {integer} second[s] end [timeout]

Syntax

With timeout of 15 seconds
End timeout

Description

The with timeout statement allows you to alter AppleScript's default 60-second time limit for the Apple events that are sent to applications. Normally, if an application fails to respond to an Apple event within 60 seconds, AppleScript raises an "Apple event timed out" error and stops running the script. You can make this time limit shorter, say 30 seconds, by using the syntax:

with timeout of 30 seconds...end timeout

You enclose the with timeout structure in a try block to trap and report any timeout errors (see "try"). with timeout only applies to the following types of commands. In other words, the with timeout limit is ignored unless the command is one of these types:

Examples

The following example times out if you just let the display dialog dialog box sit there for over five seconds. This happens because the display dialog scripting addition is positioned inside the tell block targeting the Finder. Pull the scripting-addition command outside the tell block, and the script does not time out. Again, with timeout does not work with scripting-addition commands unless the command is part of a tell block targeting another application, or it takes an application object as a parameter:

try -- catch any timed out errors
   with timeout of 5 seconds
      tell application "Finder"
         get version
         display dialog "fast" (* let this sit for about 5 secs and raise 
         an error *)
      end tell
   end timeout
on error -- will be called if 'with timeout' block times out
   display dialog "Sorry, the operation timed out"
end try

TIP:   If an AppleScript that sends an Apple event to another application times out, the Apple event itself is not cancelled (with or without a with timeout statement). So the script might have timed out, but the application could still eventually respond to the Apple event that the script sent to it.

with transaction [session object] end [transaction]

Syntax

With transaction
   (* code statements here *)
end transaction

Description

with transaction is designed to group together its enclosed statements and commands by assigning each of them a single transaction id. If a database application supports with transaction, for instance, than it knows which Apple events or commands share a transaction and can initiate an appropriate response, such as locking the particular table from other users until the transaction is complete. What is a transaction? A transaction gathers together a group of operations and declares, in essence, that, "we're all in this together--if one of us fails, then we all fail. We won't signal a successful completion until we all succeed."

The with transaction statement itself, beyond assigning the transaction id, does not have any other transactional-related capabilities such as rolling back all of the statements if one of the statements (e.g., a statement that updates or alters a database file) within the transaction fails. Any behavior that commits or rolls back database changes that are part of a single transaction would have to be initiated by the database system itself (the database program that AppleScript is scripting). with transaction only works with the database programs that support this statement.

Examples

To show what the with transaction statement looks like, the following AppleScript requests the first database record from an open FileMaker database. It encloses this request in a with transaction block:

tell application "FileMaker Pro"
    with transaction
        get the first record in the database named "Mydatabase" 
    end transaction
end tell

In this case, if you watch the Script Editor Event Log window as you run the script, FileMaker converts the with transaction statement to its own begin transaction command. This command returns an integer, the transaction id, such as 2812565. You can include an optional session-object parameter with the with transaction block, but not all applications support it. If you want to use AppleScript, transactions, and databases, then you have to evaluate the particular database system's support for with transaction.

Back to: AppleScript in a Nutshell


O'Reilly Home | O'Reilly Bookstores | How to Order | O'Reilly Contacts
International | About O'Reilly | Affiliated Companies

© 2001, O'Reilly & Associates, Inc.
webmaster@oreilly.com