DekGenius.com
Team LiB   Previous Section   Next Section

1.6 Diving In

No doubt there are readers who are eager to dive into AppleScripting before they go on to this book's upcoming language reference. This section summarizes the important AppleScript language elements you need to know before you start coding:

  • Case sensitivity

  • Statement termination

  • Line continuation character

  • Naming identifiers or variables

  • Variable declaration

  • Comments

  • Data types

  • Operators and reference forms

  • Flow-control statements

  • Subroutines

  • Script objects and libraries

All of these language elements are described in more detail in Part II (except for case sensitivity and statement termination, which are taken care of adequately in the following sections).

1.6.1 Case Sensitivity

Unlike other scripting languages such as JavaScript and Perl, AppleScript is not case-sensitive. In other words, MYVAR is the same as myvar, or myfunc is the same as MyFunc in terms of function definitions. Script Editor will not let you define two functions with the same name, even if their letters are different combinations of upper- and lowercase characters. The numerous AppleScript constants and reserved words (case, current application, and other constants are covered in Chapter 6) cannot be reused as your own variable or method names. A script can change the values of predefined variables such as pi or space; however, scripters are better off using these predefined variables for the variables' intended purpose and creating their own variable names. Script Editor sees "pi" and "PI" as the same thing ("PI" would be corrected to "pi" when you compile the script). Class and command names within applications, while mostly lowercase, are corrected when you compile the script to the spelling that is specified in the app's dictionary. (Chapter 2 explains an application's dictionary.) For instance, if you typed the class name tcpip v4 configuration into Script Editor, inside of a tell app "Network Setup Scripting" block, it would be corrected to "TCPIP v4 configuration" when the statement was compiled.

1.6.2 Statement Termination

You don't have to terminate an AppleScript statement using any special characters, as you do with Perl (the semi-colon character). You do, however, have to complete each statement on a line before you go on to the next statement, unless you use the continuation character (¬ ).

1.6.3 Line Continuation Character

You can split a very long statement into several lines by typing Option-Return on the Macintosh. This produces a continuation character (¬). This character only affects how the code looks in Script Editor and is not part of the compiled code. If you store a string literal in a variable, however, and add a continuation character to the middle of the literal string, then this character becomes a visible part of the compiled string of characters (you usually want to avoid this). Splitting long code statements with the continuation character makes the script more readable. You will use this character often.

1.6.4 Naming Identifiers or Variables and Functions

The names that you create for variables and functions have to begin with a letter or underscore character ( _ ), but subsequent characters can include letters, numbers, and underscores. In variables or function names, you cannot include AppleScript's reserved words and operators such as *, &, ^, or + (covered in Chapter 4) or special characters such as $, @, or #. An exception to this AppleScript rule allows for the creation of weird variable or function names if you use vertical bars (|) to begin and end the identifier, as in: set |2^$var| to 25. The variable |2^$var| is actually valid. If you wanted to create the equivalent of a Perl scalar variable in AppleScript, you could use: set |$perlVar| to 25. There is no practical limit to the size of AppleScript variable names; that is, you can have a variable name that has up to 251 characters, but you would never want to deal with variable names that long. In my OS 9 testing, a variable name that exceeded 251 characters produced the error dialog in Figure 1-10.

Figure 1-10. Script Editor signals a variable name that's too long
figs/ascr_0110.gif

1.6.5 Variable Declaration

You can use either the set or copy keywords to declare a variable and assign a value to it, as in the following examples:

set myvar to (5 * 25)
copy (5 * 25) to myvar

Both of these statements produce the same result; they store the integer 125 in the myvar variable. The set version however is more intuitive and is used more often to declare variables. set and copy furthermore have different results when you use the variable to contain a list, record, or script object. (Chapter 9, discusses this AppleScript feature.) The copy keyword, as in:

copy listVar to newListVar

will make a new copy of the list value stored in listVar and store this new list in newListVar. If you used:

set newListVar to listVar

the list stored in newListVar will still refer to the original list (i.e., listVar). The newListVar variable will not get a new copy of the list when you use set. Chapter 6 goes further into this set and copy subject.

1.6.6 Comments

Comments are the descriptions that you add to the code as reminders to yourself and guidance to other coders; they are not part of the executable script. AppleScript uses two or more dashes (—) preceding the comment text for single-line comments and (* *) surrounding the comment text for single- or multi-line comments. Using dashes, you can have a comment on the same line as some code, such as:

set myvar to 10 -- initialize myvar to 10.

AppleScript does not use the popular slash-slash (//) single-line comment characters of Java or C++.

1.6.7 Data Types

Like most scripting tools, AppleScript is a "loosely typed" programming language. This means that for the most part you do not have to specify exactly how the computer will store some data when you set a variable to a value. AppleScript takes care (or tries to) of the details for you. So when you use the code fragment: [set num to 75], AppleScript knows that num is an integer or number. If you use:

set numstr to "I'm a string"

numstr is automatically stored as a string. This feature does not forbid you from specifying the data type of a variable, which is a good idea in many situations and creates more readable code. If you want to explicitly set a variable to an AppleScript data type, use the as keyword, as in get current date as string. If you want to ensure that a number will be stored as a real data type, use code such as:

set num to 75.0

This code sets the variable num to a real data type, which is a very large number that can include a decimal point, similar to a double type in Java. A program can now increment or increase the variable num to a much higher number than it could if it were left as an integer, which has a range of -536,870,911 to 536,870,911, inclusive. What if you wanted to have a variable keep track over time of the number of people on Earth who are connected to the Web? This number would eventually exceed one billion, so you would want to use a variable of a real data type.

However, explicitly setting data types in AppleScript is also a potentially error-prone strategy if you are not careful in your script planning. For example, the code: set num to 1.5 as integer will compile but raise an error once the script is run. The error message is "Can't make 1.5 into an integer." If you left the as integer part out of the code fragment, then AppleScript would automatically set num to a real data type and no error would occur.

The following list briefly describes the other principal data types that AppleScripters should be aware of (these are all covered in more detail in Chapter 3):

boolean

The literal words true or false, or an expression that evaluates to true or false. AppleScript does not treat other types of "true- or false-type" values, such as or 1, as boolean values. Example 1-8 shows two ways to derive and store boolean values in AppleScript.

Example 1-8. Boolean Values in AppleScript
set bool to false -- bool is a boolean data type
set bool to (5 > 3) 
(* bool is a boolean because the expression "(5 > 3)" evaluates to true *)
date

Set a variable to a date value with code such as:

set theDate to date "12/5/2000"

Remember to use the date keyword followed by the date string ("12/5/2000"), or the theDate variable is stored as a string type. A common error is to type something like set the Date to "12/5/2000", which stores a string data type in theDate, not the date value that the scripter is aiming for. A lot of scripts get an initial date value from the useful scripting addition current date. When this command is used in a script, it returns a date object representing the current date and time, as in:

date "Tuesday, December 05, 2000 12:00:00 AM"

Appendix A, describes the current date command.

String

A series of letters, spaces, numbers, or other characters delimited by double-quote marks, as in "c" or "Here is a longer string" or "" (an empty string, but a valid string nonetheless). Suffice it to say, you deal with strings all the time in AppleScript as you read data from or write data to files, database records, and other storage media. AppleScript does not allow you to define a string with single quotation marks; you have to use double quotes. Once you have a string type, then you can get its length property (an integer), which is the number of characters that are in a string. You can use a phrase such as current date as string whose return value looks like:

"Tuesday, December 05, 2000 2:59:30 PM"

A string also has several elements such as words. The code fragment:

words of "four score and seven years ago"

returns a list type of all the words in the string (i.e., {"four", "score", "and", "seven", "years", "ago"}). You can concatenate two strings to make one string using the concatenation character ("&").

List

Called an array in other languages like Perl or Java. In AppleScript, you can store values of several different data types, including strings, numbers, and other lists, in the same list. Example 1-9 stores a string, a number, a list, and the pi predefined variable in the same list. You can see how incredibly useful this data type is; you will deal with lists all the time as an AppleScripter.

Example 1-9. AppleScript List Type
set myString to "A list that stores a string, a number, a list, and a¬ 
constant."
set myList to {myString,75.0,{1,2,3},pi}
(* Return value of this script:
{"A list that stores a string, a number, a list, and a constant.", 75.0, 
{1, 2, 3}, 3.14159265359}
*)

Lists are surrounded by curly braces ({ }), and a comma separates each list member. Variables that contain values, such as myString in Example 1-9, can also be stored in lists. Lists have three properties: length, rest, and reverse. length returns the number of list members, as in 4 for the list in Example 1-9. rest returns all the list members except for the first one, so the return value of rest of myList (from Example 1-9) would be {75.0, {1, 2, 3}, 3.14159265359}. Finally, reverse gives you the list with all of its members displayed in reverse order, as in:

{3.14159265359, {1, 2, 3}, 75.0, "A list that stores a string, a
number, a list, and a constant."}

You can obtain a member of a list by using the syntax item and the indexed position of the list member, as in:

item 4 of myList

This code returns the value 3.14159265359. Lists are one-based, meaning that the first list member is located at position 1, not as in other languages' array implementations. Finally, you can concatenate or combine two lists by using the & operator. In Example 1-9, the code:

myList & "Another string"

attaches "Another string" to the myList list variable and makes it the last list member.

Record

A record consists of a series of name/value pairs separated by commas and surrounded by curly braces. Perl would call this an associative array, or Visual Basic would call it a collection. Examples are {name: "AppleScript In a Nutshell", subject:"AppleScript"} and {first:"Bruce"}. You can refer to the members of a record by the property name, as in:

subject of {name: "AppleScript In a Nutshell", subject:"AppleScript"}

This returns "AppleScript". Records do not have item elements, so you cannot use the code item 1 of {first:"Bruce"}. You can change or coerce a record into a list, thus altering the data type of the value. An example is:

set nw to {name: "AppleScript In a Nutshell", subject: &¬ 
"AppleScript"} as list

The return value loses all the property names from the original record: {"AppleScript In a Nutshell", "AppleScript"}.

1.6.8 Operators and Reference Forms

An operator is a symbol or token that is used with values or variables in an AppleScript expression. An example is the well-worn expression 2 + 2 = 4 (if you just dropped this expression into a Script Editor window, it would return a boolean value of true). The operators in this expression are "+" and "=". AppleScript has most of the operators that you would expect a scripting language to make available to the programmer. AppleScript also allows the scripter to use very readable English expressions for operators, such as:

if 5 is greater than 3 and 6 equals 6 then set bool to true

The principal symbolic operators are demonstrated in Example 1-10. All operators, including the English forms, are described in Chapter 4.

Example 1-10. AppleScript Operators
(* & concatenates one string to another, or combines two or more lists or 
records *)
set twoPhrases to "One phrase " & "connected to another phrase."

(* the following code returns {"a string inside of a list", "added at the end 
of a sentence."} *)
set twoLists to {"a string inside of a list"} & {"added at the end of a 
sentence."}
(* & also combines two records to make one record. *)
set twoRecs to {firstn:"Amanda"} & {secondn:"Smith"}

(* parentheses and Math operators do what you would expect them to *)
set int to (5 * 6) - 8 -- returns 22

(*If you use / or ÷ the result is always a real data type. If you use 
div the 
result is always an integer *)
set n1 to 50 / 26  -- returns 1.923076923077
set n2 to 50 ÷ 26  -- returns 1.923076923077
set n3 to 50 div 26  -- returns 1; div only returns integer data types

(* <  >   = are used to test equality *)
set bool to 50 < 26 -- bool is false
set bool to 50 > 26 -- bool is true
set bool to 50 = 26 -- bool is false
set bool to 50  26 -- bool is true

(* ^ is the exponentiation operator *)
set n1 to 50 ^ 2 -- n1 is 2500.0, a real data type

(* mod returns the fractional part and throws out the rest of the integer 
part, the opposite of div which throws out the fractional part *)
set n2 to 7 mod 3 -- n2 is 1

(* not, or, and are boolean operators; they are used to combine two expressions
to produce a boolean result *)
set bool to true and false -- bool is false
set bool to true or false -- bool is true
set bool to not true -- bool is false
set bool to (2 + 2 = 4) and (not (2 ^ 2 = 4)) (* you can combine expressions
to get a result; bool is false in this case because the second part of the 
expression (i.e., (not (2 ^ 2 = 4)) ) evaluates to false *)

A reference form is an English or symbolic expression that describes where a value is within its container. As an AppleScripter, you will often find yourself describing contained objects in order to accomplish your task, such as "get the first record in the database named myDB" or, "get the second paragraph of the last document in the folder named January Stuff." AppleScript offers numerous ways to refer to these contained items. Chapter 4 goes into great detail in describing these methods, which are demonstrated in short by Example 1-11. For example, you can describe contained items by referring to the first-tenth item, then with anything that requires a reference that exceeds 10 you use the number, as in: get the 1000th word of document "Mydocument".

Example 1-11. Different Ways to Refer to Contained Items
tell application "Finder" to get the folder after (the 20th folder of startup 
disk)
(* gets the folder object after the 20th folder on the startup disk *)
tell application "Finder" to get the folder after the 20th folder of¬ 
startup disk
tell application "Finder" to get the folder before the 20th folder of¬
startup disk

You can create very useful and detailed scripts using AppleScript's numerous reference forms. Example 1-12 gets only one part of a list of numbers (i.e., the numbers 3 through 6) and stores this sub-section in another list variable. The following section briefly describes the repeat and if...end if statements that appear here.

Example 1-12. Using the Range Reference Form
set list1 to {1, 2, 3, 4, 5, 6}
set list2 to (numbers 3 thru 6 in list1) -- returns only {3,4,5,6}

1.6.9 Flow-Control Statements

AppleScript includes syntax that you can use to test expressions and only have some code execute if certain conditions are met, as well as loop through code statements and then exit from the loop. These programming constructs are often called flow-control statements. These statements are covered extensively in Chapter 7.

Like many other programming languages, AppleScript uses an if...then...else...end if statement to test various expressions. AppleScript also has an if simple statement and an if compound statement (one that extends over several lines). For example, you can use code such as:

if numVar > 1000 then return 1000

on one line without including any end ifs. Example 1-13 includes both types of if statements.

AppleScript uses several variations of the repeat statement to loop through code (see Example 1-13). Repeat is AppleScript's version of the for (;;;) or while... or foreach... loops of other languages like Perl or Java. AppleScripters often use repeat to loop through the values of a list. For example, the code:

repeat with m in listVar...end repeat

will loop through all of the list members stored in the variable listVar. Within the loop, the iterator variable m will sequentially contain each list-member value. Example 1-13 includes several versions of the repeat and if...end if statements.

Example 1-13. AppleScript if and repeat Statements
set userNum to 75.66
 (* compound if statement *)
if the class of userNum is real then
   display dialog "It's a real number."
else if the class of userNum is integer then
   display dialog "It's an integer."
else
 (* you can include a final else as part of the test; in this case it is not 
necessary *)
end if

(* simple if statement *)
if userNum is greater than 100 then display dialog "The value exceeds 100."

(* various repeat loop variations *)
repeat 10 times
   set userNum to userNum + 1
end repeat

(* endless loop without 'exit repeat' *)
repeat
   exit repeat -- this loop only iterates once because of exit
end repeat

repeat while userNum  < 10000
   set userNum to userNum * 2
end repeat

(* if the statement following 'until' evaluates to 'true' then the repeat 
statements are not executed *)

repeat until userNum >100000
   exit repeat (* this exits from this loop right away; you could do 
something else if you wanted to *) 
end repeat

set myList to {1,2,3,4}
(* repeat statement that iterates over list contents *)
repeat with mem in myList
   set userNum to userNum + mem
end repeat

(* A different kind of repeat loop *)
repeat with loopVar from 2 to 10 by 2 (* loop circles five times; loopVar
is 2,4,6,8,10 *)
   --do something here
end repeat

Another important statement construct in AppleScript provides the language with error-trapping capability. It is called the try statement, and looks like try...on error...end try. try is similar to Java's try...catch( ) statement. If you enclose a series of AppleScript statements in a try block and one of them raises an error, AppleScript will "catch" the error and allow you to deal with it in a responsible manner. Without using a try statement, a run-time error will cause a script to display an error message, and then terminate the script execution. Example 1-14 demonstrates how to use the try block. Again, Chapter 7 thoroughly describes these statements and others.

Example 1-14. Trapping Errors with try
try
   set aNum to (text returned of (display dialog¬
      "Enter a number." default answer ""))
   set aNum to aNum as real
on error errmsg
   display dialog "It looks like you did not enter a number: " & errmsg
end try

1.6.10 Subroutines

Subroutines are code units that can be used over and over again throughout the script once they are defined in the AppleScript program. They are essentially user-defined commands. Subroutines or handlers in AppleScript can be called with or without parameters, similar to functions in other languages. The subroutine can return a value to the calling script or simply perform a task and exit without returning a value. You can do almost whatever you want in a subroutine (except define another subroutine within it), including declare and initialize variables and call other functions. Example 1-15 creates a simpler way of producing a character from its ASCII decimal number equivalent. It calls the ASCII character scripting addition to produce the value.

Example 1-15. Simple AppleScript User-Defined Subroutine
set let to chr(67)-- the variable is set to 'C'
on chr(int)
   return ASCII character int
end chr

To define a subroutine in AppleScript, use the keyword on followed by the subroutine name, an opening parenthesis character, one or more optional variables that represents any subroutine arguments, and a closing parenthesis. If you have more than one parameter, then separate them with commas. Subroutines that do not have any parameters require empty parentheses, as in on chr( ). The end chr part, or simply end, is also required (Script Editor will automatically add the name of the subroutine after end if you forget to do it yourself). Whatever you want the subroutine to do is defined within the on char( )...end block. A return statement will immediately return from the subroutine, and it will optionally return a value, as in return "finished" (the subroutine would return a string "finished"). You can pass objects (such as dates) to a subroutine as parameter values. Example 1-16 returns the difference in days between two dates.

Example 1-16. Getting the Difference Between Two Dates
set dayDiff to getDiff(current date, date "Sunday, January 1, 1984 12:00:00 AM")
on getDiff(date1, date2)
     if date1 > date2 then
        return ((date1 - date2) / (24 * 60 * 60))
     else
     (* if the dates are equal then the subroutine returns 0.0 *)
        return ((date2 - date1) / (24 * 60 * 60))
     end if
end getDiff

Subtracting one AppleScript date object from another returns the difference between the two dates in seconds. This subroutine processes the seconds to return the difference in days (the result is a real data type, so it might look like 6185.835706018518, which is almost 6,186 days). Example 1-15 and Example 1-16 both show that you can call a subroutine higher up in a script than where its definition appears.

1.6.11 Script Objects

Script objects give AppleScript very basic object-oriented features, including inheritance. A script object is defined in a script-code block that looks a little like a subroutine definition. Script objects are created within a script with the script [script name]...end script syntax. Example 1-17 contains a simple script object definition. The object has two methods: one returns a property value and the other method increments the value of the property by one. The bottom of the script creates two copies of this object then calls its methods and displays the results.

Example 1-17. Creating a Script Object
(* begin the script object definition *)
script Test
   property myval : 0 -- one integer property
   on getVal(  ) -- define a method
      return myval -- return the prop value
   end getVal
   on upVal(  ) -- define another method
      set myval to myval + 1 -- increment myval property  by one
   end upVal
end script -- end script object definition
copy Test to t1 -- create new Test object
copy Test to t2 -- create another, different Test object
(* two ways to call an object's methods *)
tell t1 to upVal(  )
t2's upVal(  )
t2's upVal(  ) (* t2's upVal method is called twice, setting its myval property
to 2 *)
set theMessage to "t1: " & (t1's getVal(  ) as string) (* find out the two
object's property values *)
set theMessage to theMessage & return & "t2: " & (t2's getVal(  ) 
as string)
display dialog theMessage

You may have noticed the use of the keyword copy to create the two Test objects in Example 1-17. The copy keyword creates a new copy of the object and stores it in the named variable, as in [copy Test to t1]. If the script used set t1 to Test and set t2 to Test, then the variable t2 would not have a new copy of the Test object. It would refer to the same Test object (and the same myval property) as the t1 variable.

Libraries present a real-world use of script objects. A library, which is a type of script object, can be one or more method definitions stored as a compiled script. To use the library's methods, load it into the script with the load script scripting addition (Example 1-18 and Example 1-19 demonstrate this).

Example 1-18. Defining a Library
(* define some methods and save as an applet or compiled script; 
the file name of the script is "farewell"
*)
on sayGoodbye(  )
   display dialog "Goodbye"
end sayGoodbye
on sayCiao(  )
   display dialog "Ciao"
end sayCiao

Now load the library into any old script by providing its file path (where the script is saved on the computer) as a parameter to the load script scripting addition.

Example 1-19. Using a Library
set bye to load script "macintosh hd:desktop folder:farewell"
 (* call library methods *)
bye's sayGoodbye(  )
bye's sayCiao(  )

Chapter 9 goes into much greater depth on script objects.

    Team LiB   Previous Section   Next Section