BUY THIS BOOK

Safari Books Online

What is this?

Looking to Reprint this content?


AppleScript: The Definitive Guide
AppleScript: The Definitive Guide

By Matt Neuburg

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Ways to Use AppleScript
If you've never used AppleScript before, you probably have two questions at the outset. You might like to know: "What is AppleScript?" And you also might like to know: "And why should I care, anyway?" This chapter gives general answers to both questions, by focusing on the question: "What is AppleScript for?" The chapter classifies the main kinds of use for AppleScript, and provides some examples showing AppleScript being put to these various kinds of use.
The purpose of this chapter is as much motivational as informative. By demonstrating AppleScript in action, in some typical real-life contexts, I hope to get you thinking by extension about ways in which you might now or in the future want to use AppleScript in your own life. If you can mentally formulate some appropriate tasks you actually want to perform with AppleScript, you'll have more reason to learn it, and you'll learn it more easily and more enjoyably.
As you know, you've got various applications on your computer, and you typically make them do things by choosing menu items and clicking buttons and generally wielding the mouse and keyboard in the usual way; and you get information from them by reading it off the screen, or you can communicate information from one application to another by copying and pasting.
With AppleScript, you can make applications do things, not with the mouse and keyboard and screen, but programmatically—by writing and executing a little program that gives an application commands and fetches information from it. In the chain of actions that you make the application perform, the program that you write takes the place of your brain; the program's power to give commands to the application takes the place of your hands on the mouse and keyboard, and its power to ask the application questions takes the place of your eyes reading the screen. Thus, you can automate the sorts of things you're accustomed to making applications do manually. Instead of your doing something with the mouse, then reading the screen, then thinking about what this means and what you should do next, and so forth, the computer does the doing, the reading, and the thinking. This means that your hands and eyes and brain are freed from having to perform repetitive or tiresome activities better suited to the computer itself.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Nature and Purpose of AppleScript
As you know, you've got various applications on your computer, and you typically make them do things by choosing menu items and clicking buttons and generally wielding the mouse and keyboard in the usual way; and you get information from them by reading it off the screen, or you can communicate information from one application to another by copying and pasting.
With AppleScript, you can make applications do things, not with the mouse and keyboard and screen, but programmatically—by writing and executing a little program that gives an application commands and fetches information from it. In the chain of actions that you make the application perform, the program that you write takes the place of your brain; the program's power to give commands to the application takes the place of your hands on the mouse and keyboard, and its power to ask the application questions takes the place of your eyes reading the screen. Thus, you can automate the sorts of things you're accustomed to making applications do manually. Instead of your doing something with the mouse, then reading the screen, then thinking about what this means and what you should do next, and so forth, the computer does the doing, the reading, and the thinking. This means that your hands and eyes and brain are freed from having to perform repetitive or tiresome activities better suited to the computer itself.
Suppose, for example, you've got a folder full of image files and you want to change their names in a systematic way to image01.jpg, image02.jpg, and so forth. It isn't as if you don't know how to do this. You select the first image file with the mouse, press Return to start editing its name, type image01.jpg, and press Return again. Now you select the next image file with mouse, and do it again. The business of doing it again rapidly becomes tiresome and error-prone. You have to remember where you are ("What was the number I assigned to the previous image file I renamed?"), think what to do next ("What do I get when I add 1 to the previous number?"), and do it (click, Return, type, Return). It isn't long before you're making mistakes clicking or typing, or your eyes are starting to go out of focus, or you are just plain bored out of your skull.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Is This Application Scriptable?
Our first rule of thumb for when AppleScript is appropriate is that you should have a scriptable application that you want to automate with it. That's because AppleScript, although it is a genuine programming language with some interesting and useful features, is intended for use with other applications, which are expected to provide the real muscle. Thus AppleScript's numeric abilities are limited (it has no built-in trigonometric or logarithmic functions) and its text processing facilities are fairly rudimentary (it doesn't support regular expressions and isn't even very good at extracting substrings). So, for example, if I wanted to remove a text file's HTML markup, or extract the headers and bodies of all the messages in an .mbox file, I'd be far happier using Perl. On the other hand, AppleScript can drive Perl (and vice versa), so in your AppleScript code you can take advantage of Perl's powers (and vice versa); we'll see several examples later in the book. Thus success might simply be a matter of combining specialties appropriately.
Using AppleScript with a scriptable application is not itself a panacea. First you need a scriptable application that has the capabilities to do what you want. And even such an application might not provide a way to script those particular capabilities. Still, you can't worry about that if you don't know whether an application is scriptable in the first place!
Here's the most reliable way to ascertain whether an application is scriptable. Start up Apple's Script Editor program. (It's in /Applications/AppleScript.) Choose File Open Dictionary. This shows you a list of applications on your computer that the Script Editor thinks are scriptable. Initially, this list might omit some applications, so you can press the Browse button to locate an application using the standard Open dialog. If an application is dimmed here, it isn't scriptable. To double-check, choose and open an application. If a Dictionary window appears, the application is probably scriptable; but this could be a false positive. Make sure that the left side of the Dictionary window lists commands other than the "required" commands
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Calculation and Repetition
Computers are good at calculation and repetition—which happen to be exactly the things humans are not good at. Humans are liable to calculate inaccurately, and repetitive activity can make them careless and bored. The whole idea of having a computer is to have it take over in these situations.
Here's an example. Someone on the Internet writes: "I want to rename a whole lot of image files based on the names of the folders they're in." One can just picture this user's eyes glazing over at the thought of doing this by hand. This is just the sort of thing a computer is for.
The task would make a good droplet. A droplet is a kind of applet, which is a little application you write with AppleScript, such that you can drop the icons of files and folders onto the droplet's icon in order to process those files and folders in some way. (See Section 4.6 and Section 24.1.) So here's the AppleScript code for a droplet where you drop a folder onto its icon and it renames all the files in that folder as the name of the folder followed by a number:
on open folderList
        repeat with aFolder in folderList
                tell application "Finder"
                        if kind of aFolder is "Folder" then
                                my renameStuffIn(aFolder)
                        end if
                end tell
        end repeat
end open
on renameStuffIn(theFolder)
        set ix to 0
        tell application "Finder"
                set folderName to name of theFolder
                set allNames to name of every item of theFolder
                repeat with aName in allNames
                        set thisItem to item aName of theFolder
                        set ix to ix + 1
                        set newName to folderName & (ix as string)
                        try
                                set name of thisItem to newName
                        end try
                end repeat
        end tell
end renameStuffIn
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Reduction
A script is a means of reduction: it combines multiple steps into a single operation. Instead of doing one thing, then another, then another, you do just one thing—run the script. I particularly like using AppleScript for reduction. Having worked out a series of steps to accomplish a task, I often realize that not only do I not want to have to go through them all again later, but also I fear I won't even remember them again later! My AppleScript program remembers the steps for me.
Here's an example. From time to time I have to reboot my computer into Mac OS 9. The drill is: open System Preferences, switch to the Startup Disk pane, click the Mac OS 9 System folder, hold the Option key, click Restart. Too much work! Too many steps, too much waiting, too much hunting for the right thing to click on, too much clicking. Here's the script that does it for me:
try
        do shell script ¬
                "bless -folder9 'Volumes/main/System Folder' -setOF" ¬
                        password "myPassword" with administrator privileges
        tell application "System Events" to restart
end try
I've got that script saved as an applet, which is a little application written with AppleScript. To run the script in an applet, you just open the applet like any application. So this applet is sitting right on my desktop, where I can't miss it. To restart into Mac OS 9, I just double-click it. Now that's something I can remember.
Here's another example. A journal for which I occasionally write articles requires me to submit those articles in XML format. It happens that the XML editor I use inserts line breaks; the magazine doesn't want those. In practice the problem arises only between <Body> tags. So this BBEdit script post-processes my XML output, removing the line breaks between <Body> tags just before I send an article off to the magazine:
tell application "BBEdit"
        activate
        repeat
                find "<Body>([\\s\\S]*?)</Body>" ¬
                        searching in text 1 of text window 1 ¬
                        options {search mode:grep, starting at top:false, 
                        wrap around:false, reverse:false, case sensitive:false, ¬
                        match words:false, extend selection:false} ¬
                        with selecting match
                if not found of the result then
                        exit repeat
                end if
                remove line breaks selection of text window 1
        end repeat
end tell
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Customization
It's hard to write an application that meets everyone's desires and expectations; perhaps it's impossible. It's not just a matter of features; it's a matter of psychology. The software developer can't anticipate exactly how you'd like to use the software. By making the software scriptable, the developer can greatly reduce this problem. Instead of berating developers for not including that one menu item that would do just what you want, you get to applaud them for making the application scriptable and letting you implement the functionality yourself. If an application is scriptable, there may be much less reason for you to complain that it can't do a certain thing; quite possibly, by means of scripting, it can.
For example, Mailsmith can filter incoming email messages, and can perform various actions as part of this filtering process—but saving an email message to disk, as a text file, is not one of them. Now, you could look at this as meaning that Mailsmith can't save an email message to a file as part of a filter; but that's not really true, because Mailsmith can be scripted to save a message to a file. I subscribe to a number of mailing lists in digest form, and I like to save these as files to particular folders on my hard drive. So I have a script (not shown here) that runs through every message in the "incoming mail" mailbox, looks to see if it belongs to a mailing list, and if it does, saves it to the corresponding folder on disk and deletes it from the mailbox.
Some scriptable applications provide a means for customization at an even deeper level, by letting you modify what happens when you choose one of the application's own menu items or perform some other action in that application. For example, the Finder can be set up with Folder Actions that take over when you do things such as move a file into a certain folder. (See Section 2.5 and Section 24.3.)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Combining Specialties
Different applications are good at different things. You typically don't perform every task in a single application. Some applications do attempt to behave as "Swiss army knives" and be all things to all people (for example, Microsoft Word, a word processor, includes image-processing facilities); but on the whole, applications are specialized. Very often the point of using AppleScript is to get two or more applications working together. By sharing data, each application can contribute its own particular excellence to an operation's workflow.
Here's an example. In order to design the stop list for a web-based search engine, I needed to know the most frequently used words in each web page on the site. The web pages were easily stripped of their HTML, but then the question was how to count the occurrences of each word in a file and record the totals for the 30 most frequent words. The counting, I decided, could best be done with Ruby, a Unix scripting language I'm fond of. I wrote a little Ruby script that could be called from the command line with a file's pathname as argument:
#!/usr/bin/ruby
class Histogram
        def initialize
                @tally = Hash.new(0)
        end
        def analyze(s)
                s.split.each do |word|
                        myword = word.downcase.gsub(/[^a-z0-9]/, "")
                        @tally[myword] = @tally[myword] + 1 if !myword.empty?
                end
                @tally.sort { |x,y| y[1]<=>x[1] }
        end
end
analysis = Histogram.new.analyze(File.new(ARGV[0]).read)
The hash of words and their frequencies has now been sorted by frequency and is sitting in the variable analysis. But what to do with this data? It was decided that the most flexible approach would be to store it in an Excel worksheet for later retrieval, manipulation, and analysis. So the Ruby script now goes on to hand the data over to Excel, using AppleScript. Here's the second part of the same Ruby script:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Places to Use AppleScript
In the previous chapter you learned about the kinds of thing you can do with AppleScript. But where can you do these things? You're going to write and run some AppleScript code; where are you going to write it, and where are you going to run it? This chapter answers these questions, by surveying the many areas of your computer where AppleScript is available to you.
We've seen that the main reason for using AppleScript is in order to drive a scriptable application. AppleScript does this by sending messages, which are actually Apple events, to the scriptable application. So the scriptable application is the receiver (or target) of these messages; AppleScript, and by extension the host environment where AppleScript code is being run, is the sender . So this chapter is about the various kinds of environment you might use as a sender.
As you will see in more detail in Chapter 4, there are three stages in the life of an AppleScript program:
  1. The AppleScript code starts life as text.
  2. Then that text is compiled into a different form, one that humans can't read but that AppleScript can execute. The compiled code can optionally be saved at this point, as a compiled script file.
  3. Finally, the compiled code is executed, or run.
We are really concerned in this chapter only with the last stage—the kinds of place where compiled AppleScript code can be executed—though it happens that many such places can also compile AppleScript code, transforming it from raw text into executable form.
(In general I have had to make up some descriptive terms in order to taxonomize the kinds of sender described in this chapter, but I define those terms immediately, and I don't think this makes the taxonomy any less helpful. The example scripts in this chapter are for the most part deliberately simple and somewhat contrived; they are not intended to provide any serious illustration of the actual uses to which AppleScript might be put. That, after all, was the task of the previous chapter.)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Script Editor
By script editor I don't mean just Apple's Script Editor application—though that is in fact an example of a script editor. I mean a dedicated application intended as a general environment for the user to create, edit, compile, develop, and run AppleScript code. Typically such a program will have the following features:
  • A script can be edited within a convenient interface.
  • There is a facility for displaying the dictionary of any scriptable application, so that the programmer can learn something about how to speak to that application.
  • If a target application is recordable, user actions in that application can be recorded into a script.
  • A script may be compiled.
  • A compiled script is formatted ("pretty-printed") according to AppleScript's internal settings for fonts, syntax-coloring, and so forth.
  • A compiled script can be run.
  • When a script is run, if it yields a result, that result can be displayed.
  • A script can be saved in any of the standard formats: as text, as a compiled script, or as an applet.
  • A script can use any installed OSA language, not just AppleScript.
(Terms in that list that may be strange to you are explained in Chapter 4. That's where I'll formally introduce dictionaries, explain what it means for an application to be recordable, describe the standard AppleScript file formats, and talk about the OSA, or Open Scripting Architecture.)
Apple Computer provides a script-editing application of this kind, called (logically enough) Script Editor. It's free, and is part of the default installation of Mac OS X. It is located in
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Scripting Environment
The term scripting environment is meant to denote a small class of applications dedicated primarily to letting the user edit and run scripts in some language other than AppleScript, while secondarily providing a way to enter and run AppleScript code.
In the pre-Mac OS X world, a good example of such a program was HyperCard. HyperCard's main purpose was to allow the user to construct an interface and to associate scripts with the elements of this interface; for example, one could write a script to be run when a button was clicked. These scripts were usually in HyperCard's own internal scripting language, HyperTalk; but each script had a popup menu allowing it, alternatively, to use other available languages such as AppleScript. This was very handy because it meant you could use HyperTalk for the things HyperTalk was good at (such as driving the HyperCard interface) and AppleScript for the things AppleScript was good at (such as driving other scriptable applications).
A similar program is UserLand Frontier. Frontier also has a much less expensive "little brother," Radio UserLand; for our purposes the two programs are interchangeable. Frontier is meant to store and run scripts in UserLand's own scripting language, UserTalk; but a Frontier script can use other available languages, including AppleScript.
(The reason HyperCard and Frontier can "see" and incorporate AppleScript is that these are OSA-savvy applications: they can see and incorporate any OSA language, and AppleScript is an OSA language. Section 4.2 explains what this means.)
Figure 2-5 shows some AppleScript code being run in Radio UserLand. The AppleScript code is in the middle window, the one whose language popup (at the bottom of the window) is set to AppleScript. You should ignore the triangles at the left of each line, which are a feature of Frontier's outline-based script editing environment. In Figure 2-5, the UserTalk code in the bottom window calls the AppleScript code in the middle window and displays the result in the top window. The purpose of this arrangement is to show you how UserTalk and AppleScript can interact transparently in Frontier.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Internally Scriptable Application
A number of applications are internally scriptable. By this I mean that the application contains its own internal mechanism, possibly a proprietary language, for automating just that application. When such an application is developed for Mac OS, it sometimes happens that its developers would like to provide it with a means of communicating with other applications. That means Apple events, and AppleScript is a convenient way to send Apple events (convenient both for the developers and for the end user), so a typical approach is to let the internal scripting language treat text as AppleScript code. Such applications are not very good places to develop your AppleScript code, since you usually have no way to edit and test that code coherently inside the application. A typical approach is to develop the code in a dedicated script editing environment such as the Script Editor, and then copy it into the other application.
An example is Microsoft Word. Word comes with its own internal scripting language, Visual Basic for Applications (VBA), whose purpose is to automate Word itself. The Mac OS version of VBA also includes the MacScript function, which accepts a string and compiles and runs it as AppleScript on the fly. For more about using VBA in Word, see Steven Roman's Writing Word Macros (O'Reilly).
Constructing your AppleScript code in VBA is rather a trying experience, because you have to pass through VBA's rules about generating strings. Since AppleScript is a line-based language, line breaks in the code must be expressed explicitly; the way to do this in VBA is to call a function, Chr(13). The calls to this function must be concatenated with the rest of your string to form the AppleScript code. Quotation marks are also a cause of concern and possible confusion.
Figure 2-7 shows a Word document and the Macro dialog; we are about to run the CallASExample macro. Figure 2-8 shows the result of running this macro. The macro has placed the names of my disks at the insertion point. The way Word found out the names of the disks was by constructing and running some AppleScript code.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Script Runner
By script runner I mean an application that accepts compiled script files and runs them. It typically has no facilities for editing or compiling scripts; you create and compile the scripts in a dedicated editor such as the Script Editor, and save the script as a compiled script file. Usually the file must then be placed in a particular location where the script runner program can find it. The script runner program typically provides some sort of interface for selecting a compiled script; when you select one, the script runner causes it to be executed. Since the script is compiled beforehand, a time-consuming step (compilation) is skipped, and execution thus typically proceeds considerably faster in a script runner than it does in an internally scriptable application where the code must be compiled on the fly.
An extreme example of a script runner is the Script Menu provided by Apple. It's extreme because a script runner is all it is; it has no other purpose, and it has no other interface apart from the menu of scripts. If you don't see the Script Menu in your menu bar (it appears as a black scrolled s-shaped icon), Script Menu isn't running on your machine; you can start it up by running /Applications/AppleScript/Install Script Menu. The menu items in the Script Menu represent the folders and script files inside /Library/Scripts and ~/Library/Scripts; you can toggle the visibility of the menu items representing /Library/Scripts with the Show/Hide Library Scripts menu item. To add an item to the menu, put a compiled script file inside one of these directories. The menu is global, but if you create a folder ~/Library/Scripts/Applications/AppName (where for "AppName" you supply the name of some application), then scripts in it will appear in the Script Menu only when AppName is the frontmost application. To run a script, choose the corresponding menu item from the menu. Many of the scripts in the Script Menu are worth studying as examples of scripting techniques. (Some of them are shell scripts or Perl scripts; in general these are outside the scope of this book, but it's nice that the Script Menu can run them as well.)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Automatic Location
An automatic location can be thought of as a highly specialized type of script runner: it's a place where you can put a compiled script to have it run automatically when certain events take place.
On Mac OS X, if you want a script to run automatically when you start up, you could save it as an applet and list it in the Startup Items tab of the Accounts pane, in System Preferences. A compiled script wouldn't do here, though; it would be opened, not executed, because Startup Items is not a script runner.
A primary example of an automatic location on Mac OS X is the Finder, where you can associate scripts with particular folders by means of folder actions . Folder actions are a mechanism whereby scripts run if certain things happen, in the Finder, to the folder to which they are attached: that folder's window is opened, closed, or moved, or something is put into or removed from that folder. Naturally you don't have to respond when all of those things happen; your script will contain a specific handler for each type of action you want to respond to. (See http://www.apple.com/applescript/folder_actions/.)
Folder actions are described at length in Chapter 24, but here's a quick explanation of how to set one up. Create ~/Library/Scripts/Folder Action Scripts if it doesn't exist already. Create a script and save it as a compiled script file in that folder. Now go to a folder in the Finder and in its contextual menu choose Enable Folder Actions and then Attach a Folder Action, and in the Open dialog select your script. You can also manage the relationships between folders and scripts with the Folder Actions Setup application, which is in /Applications/AppleScript.
In this example, we'll make a folder automatically decode any .hqx files as they are put into it. Here's the script:
on adding folder items to ff after receiving L
        tell application "Finder"
                repeat with f in L
                        set n to the name of f
                        if n ends with ".hqx" then
                                tell application "StuffIt Expander" to expand f
                        end if
                end repeat
        end tell
        tell application "System Events"
                if process "StuffIt Expander" exists then
                        tell application "StuffIt Expander" to quit
                end if
        end tell
end adding folder items to
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Application
By application I mean here an application you write yourself. There are various ways to incorporate use of AppleScript into an application, and various reasons why you might do so.
Let's start with an applet. An applet is just a compiled script saved with a tiny application framework wrapped around it; you can make one in any script editor application. I can think of three main reasons for saving a script as an applet:
  • You want to be able to run the script from the Finder, by double-clicking it.
  • You want your script to process files and folders when you drop their icons onto the script's icon; an applet that does is this called a droplet .
  • You want to be able to run the script from some other environment that can launch things but isn't a script runner.
We have already seen that if you want a script to be a Startup Item, so that it runs automatically at startup, it has to be an applet. As another example, consider the toolbar and sidebar at the top and left side of a Finder window. You can put any item you like in these places; clicking an item opens it, in the sense of launching it, as if from the Finder. So items in the toolbar or sidebar cannot be mere compiled scripts if you want to run them; they must be applets (or droplets—dropping a file or folder onto a toolbar or sidebar droplet works just fine). Apple supplies a number of examples at http://www.apple.com/applescript/toolbar/.
Moving up the ladder of complexity and sophistication, we arrive at another way you can create an application using AppleScript—with AppleScript Studio. AppleScript Studio itself isn't exactly an application; it's an aspect of two applications, Xcode (formerly known as Project Builder) and Interface Builder. AppleScript Studio allows you to use AppleScript as the underlying programming language inside what is effectively a Cocoa application, instead of the standard language, Objective-C. Thus you can combine all the power of Mac OS X-native windows and interface widgets with your knowledge of AppleScript to write a genuine application. Even more amazing, it's free. AppleScript Studio doesn't give you AppleScript access to everything that Cocoa can do, not by a long chalk; but if you have some AppleScript code and you want to wrap an interface around it, AppleScript Studio can be an easy and rapid way to do so. The result will look and act like an ordinary Cocoa application; it might not even be possible for users to tell that you wrote it with AppleScript.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Unix
By the term Unix I mean the command line and other shell-related environments such as Perl and Ruby scripts. Here the important word to know is osascript . This verb is your key to leaping the gulf between Unix and AppleScript. You should read the relevant manpages. (Further details are provided in Chapter 23.)
osascript can execute a compiled script file or can compile and execute a string. The option -e signals that it's a string, not a script file, and of course if you're going to type a literal string, this raises all the usual problems of escaped characters. In the Terminal you can usually bypass these problems by single-quoting the string.
The following little conversation in the Terminal illustrates the difference in the formatting of the output depending on whether you supply the -ss flag. I generally prefer this because it does a better job of showing you what sort of reply you've really got. The curly braces and the double quotes show clearly that it's a list of strings:
$ osascript -e 'tell app "Finder" to get name of every disk'
xxx, main, second, extra
$ osascript -ss -e 'tell app "Finder" to get name of every disk'
{"xxx", "main", "second", "extra"}
In a Perl script it's rather easy to tie oneself in knots escaping characters appropriately so as to construct the correct string and hand it off to osascript. The difficulties are even worse than in the Microsoft Word example earlier in this chapter, because two environments, Perl and the shell, are going to munge this string before it gets to AppleScript. This line of Perl shows what I mean:
$s = `osascript -e "tell app \\"Finder\\" to get name of every disk"`;
The Perl backtick operator hands its contents over to the shell for execution, but first there's a round of variable interpolation within Perl; during that round, the escaped backslashes are mutated into single backslashes, and these single backslashes correctly escape the double quotes around "
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: The AppleScript Experience
This chapter illustrates informally the process of developing AppleScript code. The idea is to help the beginner gain a sense of what it's like to work with AppleScript, as well as to present some typical stages in the development of an AppleScript-based solution. My approach is to demonstrate by example, letting you look over my shoulder as I tackle a genuine problem in my real life. This chapter doesn't actually teach any AppleScript; that comes later. But the procedures and thought processes exemplified here are quite typical of my own approach to writing AppleScript code, and probably that of many other experienced users as well; as such, the neophyte may benefit by witnessing them. Besides, if you've never programmed with AppleScript before, you're probably curious about what you're getting yourself into.
Think of this chapter, then, as a nonprogrammer's introduction to the art of AppleScript development. It's the art that's important here. The particular problem I'll solve in this chapter will probably have no relevance whatever to your own life. But the way I approach the problem, the things I do and experience as I work on it, contain useful lessons. At the end of the chapter we'll extract some general principles on how to approach a task with AppleScript.
I have just completed, working in Adobe FrameMaker, the manuscript for a book about AppleScript. This manuscript is now to be submitted to my publisher. My publisher can take submissions in FrameMaker, which is what the production office uses in-house; and there is a checklist enumerating certain details of the form the manuscript should take. Looking over this checklist, I find an entry from the illustration department informing me that I'm supposed to follow certain rules about the naming of the files that contain the illustrations, and that I'm to submit a list of illustrations providing the number, name, and caption of each figure. Table 3-1 presents the example the illustration department provides.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Problem
I have just completed, working in Adobe FrameMaker, the manuscript for a book about AppleScript. This manuscript is now to be submitted to my publisher. My publisher can take submissions in FrameMaker, which is what the production office uses in-house; and there is a checklist enumerating certain details of the form the manuscript should take. Looking over this checklist, I find an entry from the illustration department informing me that I'm supposed to follow certain rules about the naming of the files that contain the illustrations, and that I'm to submit a list of illustrations providing the number, name, and caption of each figure. Table 3-1 presents the example the illustration department provides.
Table 3-1: How the O'Reilly illustration department wants figure files named
Fig. No.
Filename
Caption (or description)
1-1
wfi_0101.eps
Overview of the Windows NT operating system environment.
1-2
wfi_0102.eps
Name space presented by the Object Manager.
1-3
wfi_0103.eps
Filter drivers in the driver hierarchy.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
A Day in the Life
Although I know that FrameMaker is scriptable, I have no idea how to script it. I haven't the slightest notion how to talk to FrameMaker, using AppleScript, about the illustrations in my manuscript. So the first thing I need to do is to try to find this out.
My starting place, as with any new AppleScript programming task, is the dictionary of the application I'm going to be talking to. The dictionary is where an application lists the nouns and verbs I can use in speaking to it with AppleScript. To see FrameMaker's dictionary, I start up Apple's Script Editor, open the Library window, add FrameMaker to the library, and double-click its icon in the Library window. The dictionary opens, as shown in Figure 3-1.
Figure 3-1: FrameMaker dictionary
This is a massive and, to the untrained eye (or even to the trained eye), largely incomprehensible document. What are we looking for here? Basically, I'd like to know whether FrameMaker gives me a way to talk about illustrations. To find out, I open each of the headings on the left, and under each heading I open the Classes subheading. A class is basically a noun, the name of a type of thing in the world of the application we're talking to. So what I'm trying to find out is what things FrameMaker knows about, so that I can guess which of those things is likely to be most useful for the problem I'm facing. In particular, I'd like to find a class that stands a chance of being what FrameMaker thinks my illustrations are.
The fact is, however, that I don't see anything that looks promising. The trouble is that I don't really understand what an illustration is, in FrameMaker's terms. I know that to add an illustration to a FrameMaker document, using the template my publisher has set up, I begin by inserting a table. And sure enough, there is a table class in the FrameMaker dictionary. But then, to make the reference to an illustration file, I choose the Import File menu item, and it is not at all clear to me what kind of entity I generate as a result.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Conclusions, Lessons, and Advice
You'll no doubt have noticed that most of my time and effort working on this problem was spent wrestling with the particular scriptable application I was trying to automate. In general, that's how it is with AppleScript. AppleScript itself is a very small language; it is extended in different ways by different scriptable applications. Trying to work out what a particular scriptable application will let you say and how it will respond when you say it constitutes much of the battle of working with AppleScript.
Another feature of the struggle is that AppleScript's error messages aren't very helpful, and it lacks a debugging environment (unless you use Script Debugger as your script editor application), so it's important to proceed with caution and patience. When you try to execute a script, all you really know is that it worked or it didn't; if it didn't, finding out why isn't easy. You can see that I developed my final script slowly and in stages, testing each piece as I went along. I knew that the pieces worked before I put them into place; that way I could be pretty confident that I knew what the script as a whole would do.
Here, to conclude, are a few apophthegms to live by, derived from the foregoing. I hope you'll find this advice helpful in your own AppleScript adventures:
Use the dictionary.
The biggest problem you face as you approach driving a scriptable application is that you don't know the application's "object model"—what sorts of thing it thinks of itself as knowing about, what it calls these things, and how the things relate to one another. In this regard, nouns (classes) are much more important than verbs ( events). Most scriptable applications, especially if they are scriptable in a deep and powerful way, have lots of nouns and relatively few verbs. Notice how I did almost everything in the script with the basic built-in verbs get, set, and count; even select is fairly standard. The only unusual verb I ended up using was
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Basic Concepts
This chapter explains how AppleScript works. Its purpose is to provide you with a mental picture of what's really going on when you use AppleScript. It also acts as a kind of glossary, defining the basic terms and concepts needed for an understanding of AppleScript, but the concepts are presented in an expository order rather than alphabetically.
All subsequent chapters will presuppose some familiarity with the terms and concepts presented in this chapter. You don't have to grasp everything immediately, and you don't need to read every section with equal care. But you should at least skim this chapter in order to get your conceptual bearings. You can always come back later and reread a section if you need a refresher on the details.
Apple events lie at the heart of what AppleScript is and why you're going to use it, and having a sense of what they are will be of tremendous help to you in your AppleScript adventures.
Apple events are the Macintosh's system-level way of letting one running application communicate with another. Such communication is called interapplication communication . Apple events were introduced in 1991 as part of System 7. I refer to the two parties in an interapplication communication as the sender (the application that sends the message) and the target (the application that receives the message); I find this clearer and more instructive than the more technical terms "client" and "server."
An Apple event is an astonishingly powerful thing. Hermes-like, it crosses borders. Two completely independent applications are talking to each other. What's more, Apple events work across a network, including the Internet, so these two applications can be on different computers. Or it can be the opposite; an application can send an Apple event to itself. (Why would it want to do that? You'll find out, in Section 4.9.2, later in this chapter.)
Moreover, the range of what may be expressed in an Apple event is remarkably broad. Apple events actually have a kind of grammar: there are (so to speak) verbs and nouns and modifiers, and these are so cleverly and flexibly devised that single Apple events can be constructed to say surprisingly complicated things, such as (speaking to a word processing program), "Look at the text of your first window and give me a reference to every line of it whose second word begins with the letter t," or (speaking to an email program), "Look in the mailbox where the incoming mail is, find the first mail message with a subject that starts with the word `applescript', and move it into the `AppleScript' mailbox."
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Apple Event
Apple events lie at the heart of what AppleScript is and why you're going to use it, and having a sense of what they are will be of tremendous help to you in your AppleScript adventures.
Apple events are the Macintosh's system-level way of letting one running application communicate with another. Such communication is called interapplication communication . Apple events were introduced in 1991 as part of System 7. I refer to the two parties in an interapplication communication as the sender (the application that sends the message) and the target (the application that receives the message); I find this clearer and more instructive than the more technical terms "client" and "server."
An Apple event is an astonishingly powerful thing. Hermes-like, it crosses borders. Two completely independent applications are talking to each other. What's more, Apple events work across a network, including the Internet, so these two applications can be on different computers. Or it can be the opposite; an application can send an Apple event to itself. (Why would it want to do that? You'll find out, in Section 4.9.2, later in this chapter.)
Moreover, the range of what may be expressed in an Apple event is remarkably broad. Apple events actually have a kind of grammar: there are (so to speak) verbs and nouns and modifiers, and these are so cleverly and flexibly devised that single Apple events can be constructed to say surprisingly complicated things, such as (speaking to a word processing program), "Look at the text of your first window and give me a reference to every line of it whose second word begins with the letter t," or (speaking to an email program), "Look in the mailbox where the incoming mail is, find the first mail message with a subject that starts with the word `applescript', and move it into the `AppleScript' mailbox."
An interapplication communication can be thought of as either a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Open Scripting Architecture
In 1992-93, the founders of AppleScript had to decide where the language should live. They could have made AppleScript the internal language of a single application, like HyperCard's HyperTalk; the user would then compile and run AppleScript code entirely from within this one application. But this approach was unacceptable. Rather, they wanted AppleScript to be available everywhere. Thus the language would have to be part of the System. In creating a place within the System to put it, they generalized this place to be somewhere that not only AppleScript but any scripting language could live in. The resulting structure is the Open Scripting Architecture (OSA).
Under the OSA, a scripting language is implemented by a something called a component. (Components were not invented specially for the OSA; they existed already in connection with QuickTime.) Think of a component as a piece of self-contained functionality made available at system level so that any program can hook up to it and use it. One thing that's special about components is that they can be installed and uninstalled dynamically. So an OSA-savvy program doesn't necessarily think in terms of any particular scripting language; it asks the System—in particular, the Component Manager—what scripting languages are presently installed, and if it wants to use one, the Component Manager provides access to it.
Since components are installed dynamically, this installation must actually take place while the computer is running. AppleScript is installed as the computer starts up and simply left in place, so that it's always available. You may recall that under Mac OS 9 there was an extension called AppleScript (in the Extensions folder of the System Folder). Its job was to install AppleScript as a component under the OSA as the computer started up. On Mac OS X, the same function is performed by AppleScript.component, which is in /System/Library/Components; this type of file is called a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Script
A number of terms that are common in connection with AppleScript are used in a somewhat bewildering variety of senses. The word "script" is particularly liable to be tossed loosely about. This is unfortunate, especially since some of the meanings of "script" are important and rather technical. It's not a word one can do completely without, and so it is all the more crucial that its meaning not be blurred. This section tries to clarify the main ways in which the word "script" is used.
To "script" an application is to automate it, to drive it, to target it. People say, "I'd like to script the Finder to rename some files automatically." There is an implication that the Finder already has the power to do things to files, and that we are merely taking advantage of this power by dictating programmatically a sequence of actions that Finder should take.
This sense of "script" is formalized in the way some sources define a " scripting language." This quotation comes from the ECMAScript Language Specification (http://www.ecma-international.org/publications/standards/ECMA-262.htm):
A scripting language is a programming language that is used to manipulate, customise, and automate the facilities of an existing system. In such systems, useful functionality is already available through a user interface, and the scripting language is a mechanism for exposing that functionality to program control. In this way, the existing system is said to provide a host environment of objects and facilities, which completes the capabilities of the scripting language.
That is a perfect description of AppleScript. It has few powers of its own; it is meant primarily for controlling the powers of existing applications.
The preceding quotation from ECMA continues:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Compiling and Decompiling
Before an AppleScript program can be run, it must be compiled. To compile something means to transform it, behind the scenes, from text—the form in which a human user is able to read and edit the code—to a form consisting of actual executable instructions intended for a machine.
The nature of compiled code depends upon the nature of the engine that runs it. In the case of a C program written for a Macintosh, the engine is the Macintosh's central processing unit (CPU); so the compiled code must consist of machine-language instructions in accordance with the CPU chip's specifications. Such machine-language instructions, indeed, are the only instructions your computer can really execute, because the computer's ultimate "brain" is the CPU.
In the case of AppleScript, the engine is the AppleScript scripting component, and compiled code does not consist of anything so low-level. AppleScript compiled code is bytecode : roughly, the nouns and verbs of the original text are translated into some sort of compressed, coded equivalent (called tokens ). These tokens are meaningful only to the AppleScript scripting component's run-engine. When it runs the code, the engine still has to parse whatever tokens it meets along its path of execution, accumulating them into chunks and translating these chunks further in order to execute them. It is usual to describe a language that is compiled and executed in this way as being interpreted .
There isn't necessarily anything shameful about being an interpreted language. (After all, Java is an interpreted language, and yet some people take it seriously.) Being an interpreted language does mean that running AppleScript code is relatively slow, since the compiled code must be processed further while being run before it can really be run, and there is a heavy layer of operation (the runtime engine) between the compiled code and the CPU. Whether you'll perceive this slowness depends on the nature of the script and the speed of your computer; typically the observable bottleneck will be the time required for communicating with the target scriptable application and for that application to process commands and queries, not the overall speed of the AppleScript runtime engine.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Script Text File
The Script Editor offers the option to save a script as text (or "script text," depending what version of the Script Editor you're using). A script text file is simply a text file, such as can be opened by any word processor. No bytecode is saved into the file. (But the Script Editor does also try to compile the script even when you save it as text, which seems unnecessary.)
A script text file consists of ordinary text in the default system encoding (usually MacRoman). It has file extension .applescript on Mac OS X and is of type 'TEXT' on Mac OS 9 and earlier. The Script Editor saves such a file with both features, and it can be opened on both platforms.
A script text file can be opened with a dedicated editor such as the Script Editor. The situation is then exactly as if you had just typed the code into the Script Editor: if the code is valid and all external referents can be found, the code can be compiled and run.
A script text file cannot generally be run from a script runner application, such as the Script Menu, because the script is not compiled and the application is not prepared to do the compilation for you.
Since a compiled script file can be decompiled and edited further, as well as executed directly, what's the good of a script text file? Apple's documentation implies that it isn't much good, and calls it a "last resort" format; Apple's advice would seem to be that a compiled script file is the standard and most readily usable and communicable format, the format you would use when sending a script to someone else to be run on another machine.
However, I'm not so sure that a compiled script is so very communicable, or that it is better for such purposes than a script text file. There are various formats of compiled script file, and the new ones aren't backward-compatible: a compiled script file saved by the current version of the Script Editor can't be opened by some older versions of the Script Editor, and a compiled script bundle isn't backward-compatible to any system before Mac OS X 10.3 ("Panther"). Plus, as mentioned in the previous section, it is possible for a compiled script to face difficulties with regard to external referents that it can't locate; if these external referents can't be located at all, the script can't even be opened for editing, let alone executed. By contrast, a text file can always be opened under any system and on any machine; AppleScript and the Script Editor are present on every machine, so it is always possible, with valid code, to compile the script afresh.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Applet and Droplet
An applet is a compiled script file format that functions as an executable. A dedicated editor such as the Script Editor offers the option to save a compiled script as an applet (or "application," depending on your Script Editor version). When you open an applet from the Finder, it launches as if it were an application and its code runs. Furthermore, an applet is scriptable. In short, an applet is a simple, easy way for someone who knows AppleScript to write a little application. This application has just about no user interface to speak of (unless some is added by way of a scripting addition). But the disadvantages of this can easily be outweighed by the simplicity of writing one.
An applet is an application. It is saved in Mac OS X with file extension .app, and in Mac OS 9 it has file type 'APPL' and creator 'aplt'. The Mac OS X Script Editor saves the applet with both features. There is also a new "application bundle" format, also with file extension .app, which is not backward-compatible with systems prior to Mac OS X 10.3 ("Panther").
A droplet is a form of applet; the difference is that a droplet does something when file or folder icons are dragged-and-dropped onto its icon in the Finder. Typically it then proceeds to process those files or folders in some way. Technically, a droplet is simply an applet whose script contains an open handler for dealing with the drop. Indeed, the very same script application can operate both as an applet (it does something when it is opened by launching) and as a droplet (it does something when files or folders are dragged-and-dropped onto its icon). A droplet has a different creator type from an applet ('dplt'), and it has a different icon, which looks like an applet's icon with the addition of a downward arrow. The Script Editor makes this distinction when you save the file, based on the presence or absence of an open handler.
Since opening an applet from the Finder launches it as an application, the applet needs to be opened in some other way in order to edit its script. For example, you can choose Open from the File menu within the Script Editor and select the applet, or drop the applet's icon onto Script Editor's icon. If the applet's script was not saved as run-only, the compiled script will then be decompiled and will be displayed for further editing, exactly as if this were just an ordinary compiled script file. A running applet may also display a menu item offering a chance to edit it. Thus, saving a compiled script as an applet does not prevent you from continuing to edit and develop the script—nor does it hide the script from prying eyes (for that, you must also save the script as run-only).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Scripting Addition
A scripting addition is a code library, loaded by the AppleScript scripting component instance, that implements vocabulary extending the AppleScript language. Behind the scenes, communication with a scripting addition uses Apple events, just as does communication with a scriptable application. The difference, from the AppleScript programmer's point of view, is a linguistic one: the scripting addition's vocabulary is available to scripts compiled and run on that machine with no need to target any particular application. In other words, the extended vocabulary implemented by a scripting addition appears to the programmer to be built into AppleScript itself.
Scripting additions are typically written in a compiled lower-level language such as C. Their purpose is usually to bring to AppleScript some functionality that can be implemented in this lower-level language (possibly by calling into the Macintosh Toolbox) but is otherwise missing from AppleScript itself.
A scripting addition on Mac OS 9 is a resource file of type 'osax'. On Mac OS X it can also be a bundle with extension .osax. A scripting addition is often referred to as an osax (plural osaxen). On Mac OS 9, osaxen live in the System Folder, in its Scripting Additions subfolder. On Mac OS X the supplied osaxen live in /System/Library/ScriptingAdditions; the user may add osaxen to /Library/ScriptingAdditions or to ~/Library/ScriptingAdditions, according to the domain of their desired availability.
AppleScript is a little language, and at a very early stage it was felt to be a bit too little; so certain sorely missed featu