JETZT ONLINE BESTELLEN
Scripting and Automating Your Mac
Second Edition Januar 2006
ISBN 978-0-596-10211-1
590 Seiten
EUR32.00
Weitere Informationen zu diesem Buch
Inhaltsverzeichnis |
Rezensionen |
Inhaltsverzeichnis
- Chapter 1: Why to Use AppleScript
- InhaltsvorschauIf you've never used AppleScript before, you're probably in need of motivation as much as information. You'd like to know: "What is AppleScript?" You'd also like to know: "And why should I care, anyway?"Those are good questions, and they are best answered by a brief explanation of what AppleScript is for. Therefore, this first chapter classifies the main uses of AppleScript, along with some examples.By presenting AppleScript in action, in some typical real-life contexts, I hope to inspire you to imagine how you might use AppleScript in your own life. AppleScript is a big subject, and your best incentive to press ahead is a vision of some task you actually want to accomplish with it. At the same time, you'll have a far easier, more enjoyable experience of AppleScript if your aims are consonant with its nature and abilities.In this chapter, the examples are not intended for you to run on your own computer. This is real-life code that works on my machine, but is not expected to run elsewhere. Nor are you expected to understand the code at this point. I'm just showing it to you for purposes of illustration, so glance over it and move on! When you've read more of the book and have learned some AppleScript, you'll understand how to adapt these examples to your own purposes.Consider the many and various applications on your computer, and how you typically make them do things. With your hands, you choose menu items, click buttons, and generally wield the mouse and keyboard in the usual way. You also use applications as a source of information; you typically get this information by reading it off the screen, and you can communicate information from one application to another by copying and pasting. Mediating between your hands, your eyes, and the application is your brain: as your eyes get information from the application, your brain decides what to do next, and instructs your hands accordingly.With AppleScript, you make applications do things programmatically. An AppleScript program has the power to give commands to the application, taking the place of your hands on the mouse and keyboard, and it has the power to ask the application questions, taking the place of your eyes reading the screen; the program itself makes the decisions about what to do next, thus taking the place of your brain. Thus, AppleScript lets youEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- The Nature and Purpose of AppleScript
- InhaltsvorschauConsider the many and various applications on your computer, and how you typically make them do things. With your hands, you choose menu items, click buttons, and generally wield the mouse and keyboard in the usual way. You also use applications as a source of information; you typically get this information by reading it off the screen, and you can communicate information from one application to another by copying and pasting. Mediating between your hands, your eyes, and the application is your brain: as your eyes get information from the application, your brain decides what to do next, and instructs your hands accordingly.With AppleScript, you make applications do things programmatically. An AppleScript program has the power to give commands to the application, taking the place of your hands on the mouse and keyboard, and it has the power to ask the application questions, taking the place of your eyes reading the screen; the program itself makes the decisions about what to do next, thus taking the place of your brain. Thus, AppleScript lets you automate the sorts of things you're accustomed to making applications do manually.Why is that a good thing? For the same reason that any automation is good. AppleScript performs the same tasks you could perform manually, but it performs them faster, more accurately, and without your direct involvement—you needn't even be sitting at the computer. Some tasks, when performed manually, are tedious or repetitive or error-prone; it's downright annoying for you to have to perform them, whereas the computer never gets bored and never makes a mistake in calculation, and (let's face it) can perform them better than you.For example, suppose 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; then you select the next image file with mouse, and do it again, and so forth. The trouble is that you don'tEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Is This Application Scriptable?
- InhaltsvorschauAppleScript isn't just a language; it's an underlying technology supporting that language. Because this technology is present as part of the system, you get it for free—so you may as well take advantage of it. And because you know this technology will be present on any Mac OS computer, you can share with others any useful AppleScript program you happen to write.So AppleScript is omnipresent. But it's not omnipotent. AppleScript, remember, is all about telling an application to do automatically things of the sort you might make it do manually. But AppleScript does not let you tell every application to do everything it is capable of. AppleScript works by sending messages to the applications you are automating; these messages are called Apple events. You cannot send just any old Apple event to any old application. (Well, you can, but it might not have any effect.) The application to which you're sending an Apple event must recognize and respond to that Apple event. The ability to recognize and respond to a set of Apple events is a feature of the application. Giving the application this ability is up to the developers of the application—it isn't something that's within your power (unless you are also the developer of the application). An application that has this ability is said to be scriptable . If an application isn't scriptable, you're probably not going to be able to use AppleScript to automate it. (As you'll see in Chapter 24, there is sometimes a way around this limitation, but it should probably be used only as a last resort.) So, before you consider using AppleScript at all, you should have in mind some scriptable application that you want to automate with it.Not only is AppleScript not omnipotent; it isn't even all that potent. AppleScript is a genuine programming language with some interesting and valuable features, but it's not very powerful or useful on its own. It takes some scriptable application to give AppleScript any real muscle. So, for instance, AppleScript's numeric abilities are limited (it has no built-in trigonometric or logarithmic functions ) and its facilites for text processing are fairly rudimentary (it doesn't support regular expressions , and it isn't even very good at extracting substrings). Granted, these shortcomings aren't as significant as they used to be. Mac OS X is loaded with other scripting languages, such as Perl, which are expert at regular expressions—and AppleScript can drive Perl (and vice versa), so success might simply be a matter of combining specialties appropriately. Nevertheless, the general spirit and intention of AppleScript is that the power should be invested mostly in various scriptable applications, not in AppleScript itself.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Calculation and Repetition
- InhaltsvorschauComputers are good at calculation and repetition . Humans, on the other hand, are liable to calculate inaccurately, and all the more so in the face of repetitive activity, which can make them careless, bored, and angry. Calculation and repetition on a computer should be performed by the computer—not by a human.Here's an example straight off the Internet, where someone writes: "I want to rename a whole lot of image files based on the names of the folders they're in." One's eyes glaze over at the prospect of doing this by hand. Yet with AppleScript, it's a snap. The task would make a good droplet—a little application, written with AppleScript, with a Finder icon onto which you can drop files and folders you want processed. (More details appear in "Applet and Droplet" in Chapter 3 and "Applets" in Chapter 27.) Here's the AppleScript code for such a droplet; you drop a folder or folders onto its icon in the Finder, and it renames all items in each folder using that folder's name followed by a number:
on open folderList repeat with aFolder in folderList if kind of (info for aFolder) is "Folder" then renameStuffIn(aFolder) end if end repeat end open on renameStuffIn(theFolder) set ix to 0 tell application "Finder" set folderName to name of theFolder set allItems to (get every item of theFolder) repeat with thisItem in allItems set ix to ix + 1 set newName to folderName & ix set name of thisItem to newName end repeat end tell end renameStuffInThe parameterfolderListtells us what was dropped onto the droplet. We process each dropped item, starting with a sanity check to make sure it's really a folder. If it is, we give each item in the folder a new name based on the folder's name along with a number that increases each time.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Reduction
- InhaltsvorschauEven when a task doesn't involve repetition and calculation, it may involve many steps. If you can get AppleScript to perform many or all of those steps, you reduce the number of steps you have to perform. This can make for a noticeable improvement in your relationship with your computer, even if you perform this task fairly infrequently. Another advantage of reduction is that you no longer have to remember a sequence of steps; your AppleScript program remembers it for you.Here's an example involving URLs. Often, working in some application, I see a URL that I'd like to "go to" in the approprate manner. If it's an
httpURL, my default browser should open and fetch that page. If it's an email address, my email program should create a new message to that addressee. In some applications you can just click a URL and the right thing happens, but many applications provide no such facility, so I have to resolve the URL manually. This means I must look at the URL and decide on the appropriate helper program; then I select and copy the URL; then I somehow start up the helper program; finally, I paste the URL into the appropriate location. In a browser, I must hit Return afterwards, in order to go to that URL; in an email program, I must create a new message first, in order to have something to paste into. This doesn't sound like very many steps, but it's all very annoying, especially in comparison to those applications where the right thing just happens with a single click.The solution is an AppleScript program. I've assigned it a keyboard shortcut (ways of doing this are discussed in Chapter 2), so the procedure is this: select and copy the URL, then press the keyboard shortcut. That's a significant savings in time and trouble. Here's the script:set theProc to (get path to frontmost application as Unicode text) tell application "Finder" activate delay 1 -- give time for clip to convert from Classic set theURL to (get the clipboard as string) end tell ignoring application responses try open location theURL end try end ignoring activate application theProcEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Customization
- InhaltsvorschauNo application in the world can meet everyone's desires and expectations, because whatever the application's features, it is impossible for the developers of that application to anticipate everything that every user will wish to do with it. AppleScript can be a solution to this problem. Scriptability can provide, in essence, an entire alternative user interface: instead of the graphical user interface of buttons and menus, it's a programming interface. An application's scriptability says to you: "Here are all the types of thing this application operates on, and here are the operations you can perform on them; if none of this application's menu items and buttons and other graphical interface items performs just the sequence of operations you desire, feel free to use AppleScript to create a sequence that does."Here's a real-life example . On the Internet, someone asked about assigning track numbers in iTunes. A track number is an attribute of a song, which can be set in that song's Get Info dialog; it can be made to appear in the playlist display, and you can sort on it. Thus, track numbers can be used to control the order of playback in a playlist. This user wanted to assign track numbers immediately after "ripping" a CD to iTunes , so that the order in which the tracks appeared on the original CD, and in which they appeared in the initial playlist derived from that CD, could easily be restored within iTunes later on. In essence, the user was saying: "The tracks are already in their correct order within this playlist; how can I use that order to assign all the tracks a track number, in a single move?"My response was: "Use AppleScript." Here's a script that does it:
set i to 1 tell application "iTunes" tell (get view of browser window 1) repeat with aTrack in (get every track) set track number of aTrack to i set i to i + 1 end repeat end tell end tellAn interesting philosophical debate then ensued. The user thanked me, but expressed regret that this was the "only way" to accomplish this task; iTunes, he said, should include this feature natively. My attitude was just the opposite: thanks to scriptability, iTunesEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Combining Specialties
- InhaltsvorschauDifferent applications are good at different things. Most users don't perform all tasks in a single application. For example, in a word processor, you wouldn't expect to perform extensive editing of pictures: a document might include pictures, but you'd create and edit them in some other program, and then incorporate them into the word processing document. That's how it should be, and that's how users typically like it, especially on Mac OS X where (in contrast to previous systems) there is no significant penalty to running several applications at the same time. "Swiss Army knife" programs that try to be all things to all users generally seem bloated with unnecessary features (such as Microsoft Word, with its Photoshop-like "graphics enhancement" features).When it comes to assisting applications to combine their separate specialties, AppleScript really shines. Thanks to AppleScript, data can be moved back and forth between applications so that each can operate upon it in the appropriate manner. The result is a workflow in which multiple applications are coordinated, often without the intervention or even the awareness of the user.Take, for example, SpamSieve . This superb application uses Bayesian algorithms to distinguish between spam and nonspam email messages with astonishing accuracy—far better than those email client programs, such as Entourage and Apple Mail, that include spam filtering of their own. But SpamSieve is not itself an email client. So in order to filter out spam as your email client application receives it, that email client application and SpamSieve must cooperate. The email client receives the mail messages, and hands them over to SpamSieve for evaluation; if SpamSieve marks a message as spam, it tells the email client application, which can then take appropriate action (such as moving the message into a Spam folder). Whenever you check for new mail messages, the two-way communication between your email client and SpamSieve takes place automatically, seamlessly, swiftly, invisibly—and entirely through AppleScript. Thus AppleScript effectively incorporates SpamSieve's brain and its special kind of intelligence into your email application; the two specialties (receiving email messages and storing them in folders, on the one hand, and knowing what is spam and what isn't, on the other) are combined.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Chapter 2: Where to Use AppleScript
- InhaltsvorschauAppleScript, because it is implemented at system level, is omnipresent. Nevertheless, you do not use AppleScript at just any time and any place. AppleScript, like Archimedes' lever, may permit you to move the earth; but first, like Archimedes, you need a place to stand.The various contexts and milieus in which AppleScript code can be executed may be conveniently grouped into a few general categories; this chapter presents these categories, along with some examples. In other words, this chapter describes the main places where you can use AppleScript. You'll discover that AppleScript is lurking, ready and at your command, in many corners of your computer.The taxonomy presented here is somewhat artificial, and my names for the various kinds of context in which AppleScript can be used are mostly made up, but I don't think this makes the discussion any less useful. Bear in mind that the example scripts in this chapter are for the most part deliberately simple and contrived; the emphasis here is not on actual uses for AppleScript (as described in Chapter 1), but on places from which you can put it to use.A script editor is an application such as Apple's own Script Editor (located in /Applications/AppleScript)—a general development environment where the user can create, edit, test, and run AppleScript code. A script editor application will almost certainly be central to your experience of AppleScript. Although you may use AppleScript code in other contexts, those contexts will generally provide no facilities for working on that code. Thus, no matter where you intend to use your code, you will first develop it in a script editor; if you wish to use it in some other context, you'll transfer it to that context from the script editor when you are satisfied that it is ready. If, using it in that other context, you discover there's a problem with it, you'll probably bring the code back into your script editor to test and improve it.A script editor application will usually allow you to do things such as the following:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Script Editor
- InhaltsvorschauA script editor is an application such as Apple's own Script Editor (located in /Applications/AppleScript)—a general development environment where the user can create, edit, test, and run AppleScript code. A script editor application will almost certainly be central to your experience of AppleScript. Although you may use AppleScript code in other contexts, those contexts will generally provide no facilities for working on that code. Thus, no matter where you intend to use your code, you will first develop it in a script editor; if you wish to use it in some other context, you'll transfer it to that context from the script editor when you are satisfied that it is ready. If, using it in that other context, you discover there's a problem with it, you'll probably bring the code back into your script editor to test and improve it.A script editor application will usually allow you to do things such as the following:
-
Edit a script in a convenient interface
-
Display a scriptable application's dictionary, which describes how to talk to it with AppleScript
-
Record user actions in AppleScript form, if a scriptable application is recordable
-
Compile a script, and display the compiled script in pretty-printed format (compilation is a necessary intermediate step between editing and running AppleScript code, and functions as an initial check on that code's validity)
-
Run the script's code
-
View the result, if any, of running the script's code
-
Save the script in any of the standard AppleScript formats
(Technical terms in this list are formally introduced in Chapter 3.)There are three main candidates for use as a script editor: Apple's Script Editor , the freeware Smile, and the commercial Script Debugger. Each has its own advantages and peculiarities. You needn't feel confined to any single script editor; compiled scripts are a standard format, so any script editor can read the files of any other. (As of this writing, however, Smile still can't deal with bundle-formatted scripts.)Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Internally Scriptable Application
- InhaltsvorschauSome applications implement automation not through AppleScript but by means of some other language (possibly one unique to that application) that effectively operates entirely within that application. Such an application is internally scriptable . But even though such an application does not use AppleScript for its internal scripting, the developers might still wish it to be able to communicate with other applications. That means Apple events, and AppleScript is a convenient way (convenient both for the developers and for the end user) to construct and send Apple events. The internal scripting language can most likely operate on text, so a typical approach is to give
Figure 2-3: Script Debugger in action
Figure 2-4: Explorer view in Script Debuggerit the ability to treat text as AppleScript code (by compiling and running it). Even though you can use AppleScript code in an internally scriptable application, you wouldn't want to develop it there, as there is no provision for editing and testing your code, displaying a target application's dictionary, and so forth. Thus you'll usually develop your code in a script editor application and then copy it into the internally scriptable application.A good example is the database application FileMaker Pro . It has an internal scripting language that can execute text as AppleScript. This text can be static or constructed dynamically ("calculated"). Figure 2-5 shows a case in point, with FileMaker Pro being used to communicate via AppleScript with Apple's Mail program. The idea is that you might like to store your contacts in a true database program, but then you might like to create and send an email message to one of them in a true email client (see "Combining Specialties" in Chapter 1). Thus, the FileMaker window (in front) displays a database of contacts; pressing the "To" button causes Mail to create a new email message (in back) using the email address from the current FileMaker record.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Script Runner
- InhaltsvorschauAn application without facilities for editing or compiling scripts may nevertheless offer to execute compiled scripts for you on demand by way of some convenient interface, such as a menu . Such an application might be called a script runner . There is usually a requirement that a compiled script file be placed beforehand in some particular location where the script runner can find it. Because the script is compiled beforehand, a time-consuming step (compilation) is skipped, and execution typically proceeds considerably faster in a script runner than it does in an internally scriptable application where the code must be compiled from text on the fly.Many scriptable applications act as script runners, typically by means of a special Script menu . This behavior is helpful because, having developed a script that drives such an application in a useful way, you might like some convenient interface for executing that script on future occasions; the application's Script menu provides such an interface. Scripts in an application's Script menu do not have to target that application, but the feature makes sense, and is provided, in the expectation that they will do so. (And when a script in an application's Script menu does target that application, there is sometimes a tremendous speed advantage over running that same script from elsewhere; see Chapter 22.)For instance, as mentioned under "Customization" in Chapter 1, if you put scripts into ~/Library/iTunes/Scripts/, iTunes will generate a Script menu listing them and permitting you to run them; so that's a good place to store and access your scripts that customize iTunes.BBEdit is a particularly fine example of a script runner. Whatever compiled scripts you place in ~/Library/Application Support/BBEdit/Scripts/ will appear as menu items in BBEdit's Script menu, where a script can be run by choosing its menu item. For even more convenient access, BBEdit lets you assign keyboard shortcuts to these menu items. BBEdit also implements some further conventions that have become a sort ofEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Automatic Location
- InhaltsvorschauAn automatic location is much like a script runner. But there's a significant difference. A script runner finds compiled script files in a prearranged location and offers you an interface so that you can run them when you want to. An automatic location is a place where an application finds compiled script files and runs them automatically, with no intervention on your part. The application runs the script when it wants to—typically in reponse to the occurrence of certain events or stimuli. This doesn't mean you've no involvement, though; you were involved when you arranged for the application to find this script in this location, or to look for it in response to this particular event or stimulus.BBEdit is an example. I've mentioned (in the previous section, "Script Runner") that BBEdit will use a menu to let you run scripts it finds in a Scripts folder within ~/Library/Application Support/BBEdit/. BBEdit looks for two additional folders in that location—Startup Items and Shutdown Items. These are repositories for scripts that BBEdit will run automatically in response to being launched and being quit, respectively. Similarly, when you choose from any of BBEdit's built-in menus, BBEdit will run an appropriately named script located in the Menu Scripts folder. Now, all these scripts and folders did not come into existence by themselves; you put them there. But once you've done that, since these are automatic locations, BBEdit runs the scripts automatically when the appropriate events occur.Email clients, such as Apple's Mail and Microsoft Entourage, have "rules," which are essentially filter actions to be applied to mail messages. The usual configuration is to have these rules applied automatically when new mail arrives. One of the things such a rule can do is to run an AppleScript file. Again, these applications do not spontaneously invent the rules or include AppleScript files in them; you do that. But once you've done it, the application turns to the AppleScript file automatically in response to the arrival of new mail. iCal, too, can run an AppleScript file when the alarm for an upcoming event is triggered.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Application
- InhaltsvorschauThe reasons why an application might want to employ AppleScript are the same as the reasons why anyone else would—the application wishes to communicate with some other application by way of Apple events (see "Is This Application Scriptable?" in Chapter 1). It is possible to write an application that forms and sends raw Apple events directly, without using AppleScript; but AppleScript makes the task much easier for the developer of an application, just as it does for anyone else.To write an application that uses AppleScript, you don't have to be a professional developer who spends 15 hours a day at the computer and wears a beanie with a propeller. (Of course, the beanie can't hurt, either.) In fact, writing an AppleScript application could be as simple as saving a script from a script editor application. It may be useful to distinguish three different "levels" of application into which AppleScript can be incorporated: an applet , an AppleScript Studio application, and a standard compiled application that happens to call AppleScript. I'll just briefly survey all three levels here; the first two are revisited in more detail in Chapter 27.An applet is just a compiled script saved with a tiny application framework wrapped around it. This application framework is just sufficient to turn the script into a stand-alone application. You can make an applet very easily: save your script from within a script editor application, and as you do so, choose to save it as an Application. (You make this choice in the Save dialog; if the script has already been saved, you may need to choose File → Save As to bring up the Save dialog.) The result is an application that, when it runs, behaves almost exactly like your script when it runs.If an applet behaves like the script it contains, why would you bother to make one? Why not simply leave the script as a compiled script file? One reason would be that you want the script to run in some context where merely opening a compiled script file would not run it. One obvious example is the Finder. Let's say there's some operation you frequently need to perform, and the way you want to perform it is by double-clicking something in the Finder. Perhaps you find the Script Menu too much trouble; perhaps you like having an icon right on your desktop, where you can see and access it easily by double-clicking it. Or perhaps you don't want it on your desktop; perhaps you'd like to put it in the toolbar area of your Finder windows. (The toolbar is the area of a Finder window above the files but below the titlebar.) Single-clicking a toolbar item is exactly like double-clicking the same item on the desktop or in a Finder window. But double-clicking a compiled script file in the Finder doesn't run it; it opens the script for editing in a script editor application. On the other hand, double-clicking an applet (or single-clicking it in the toolbar) does run the script. (Indeed, Apple provides, atEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Unix
- InhaltsvorschauMac OS X, under the hood, is Unix . It is possible to use AppleScript from the Unix command line in the Terminal and from shell-related environments such as Perl and Ruby scripts, by means of the
osascriptcommand.osascriptcan execute a compiled script file or can compile and execute a string (indicated by the-eswitch).You can enter script text directly at the command line by typingosascriptand a return character, then typing the text, and finally signalling the end of the text with Control-D. There isn't much likelihood you'd want to do this, but at least it proves thatosascriptis working, and the code looks exactly like normal AppleScript:% osascript -ss tell app "Finder" get name of every disk end tell ^D {"feathers", "gromit", "Network"}(The-ssflag causes the result to appear in the familiar way that AppleScript usually formats a list of strings.)Use of a literal string on the command line raises some difficulties of escaping characters parallel to those we've seen earlier in this chapter; there are various solutions, depending on what shell you're using. In a language such as Perl, you can take advantage of the language's "here document " facility, which makes it easy to enter a multiple-line script without having to escape any quotes. Once again, the code looks exactly like normal AppleScript:#!/usr/bin/perl $s = <<DONE; tell app "Finder" get name of every disk end DONE print `osascript -e '$s'`;Chapter 25 contains full details about calling AppleScript from Unix, as well as communication in the reverse direction (through AppleScript'sdo shell scriptcommand).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Hyperlinks
- InhaltsvorschauYou can embed AppleScript code in an HTML hyperlink . The user can't actually execute AppleScript code by clicking such a link (the ability to do so would constitute a serious security hole). Rather, when the user clicks that link, the code is displayed in a script editor, ready to execute if the user desires.The mechanism involved is the
applescriptURL protocol. Thehrefattribute of the link's<a>tag must begin like this:applescript://com.apple.scripteditor?
The specification of Script Editor's bundle identifier is apparently a security measure; it is required, but it is also superfluous, becauseapplescriptURLs cannot be made to target any other script editor application by changing this value.applescriptURLs can be made to target a desired application (or applet) by means of a preference set by the user at system level. Apple provides no interface for setting this preference; but the freeware RCDefaultApp preference pane is an excellent way to do it (http://www.rubicode.com/Software/RCDefaultApp/).The next component of the URL is one of the following three expressions:action=new& action=insert& action=append&
They signify, respectively, that AppleScript code should be inserted in a new Script Editor window, placed at the insertion point in the currently frontmost Script Editor window, or appended to the end of the currently frontmost Script Editor window. (If no Script Editor window is currently open, all three have the same effect.)Finally, the AppleScript code itself appears, in this format:script=theCodeAs this is a URL, illegal characters in theCode must be URL-encoded using a percent sign and the character's ASCII value in hexadecimal; for example, a space must be encoded as%20, a quote must be encoded as%22, and a return character must be encoded as%0D. Athttp://www.apple.com/applescript/scripteditor/12.html, Apple provides a utility script that URL-encodes text that has been copied to the clipboard, and embeds it in anEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Automator
- InhaltsvorschauAutomator is a utility application, new in Tiger, that allows the user to construct a script (called a workflow ) from a series of steps (called actions) in a graphical interface without knowing a programming language. The default actions are in /System/Library/Automator/; additional actions may be installed into /Library/Automator/ or ~/Library/Automator, or they may be included in an application's bundle, where Automator can see them directly. Workflows can be saved as files to be run by Automator, as applications to be run independently (rather like an AppleScript applet), or as plug-ins for use by various applications: for example, a workflow saved as a Finder plug-in becomes a Finder contextual menu item, and a workflow saved as a Script Menu plug-in becomes a menu item in the Script Menu.The default actions include a Run AppleScript action , which lets the user incorporate AppleScript code directly into a workflow. Even more interesting, an Automator action can easily be written using AppleScript, and instructions for doing this appear in Chapter 27. An action is a useful way to distribute a piece of AppleScript code to users. You can't know, after all, exactly what a user would like to do with your code, and some users don't understand programming well enough to customize AppleScript code in a script editor themselves. An Automator action can help to solve these problems. An action can easily be positioned among other actions in a workflow that the user constructs in order to achieve a desired result. Furthermore, an action has a graphical interface, which lets the user set various parameters to the AppleScript code without coming into direct contact with that code.Figure 2-9 shows a simple Automator workflow; it puts up a dialog asking the user to chooose a folder, and lists the pathnames of the items within that folder into a new TextEdit document. Notice the graphical interface that allows the first action to be customized so that the dialog asks for a folder, not a file. Notice also the dataflow paradigm that links the actions: each action produces an output, which functions as the input to the next action in the sequence. The second action produces a list of files and folders (as aliases), but the third action expects text; nevertheless the workflow succeeds because Automator coerces from one type to another as necessary (here, turning a list of aliases into POSIX pathnames separated by return characters).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Chapter 3: Basic Concepts
- InhaltsvorschauPrevious chapters have been pure introduction. Chapter 1 has shown what AppleScript is good for; Chapter 2 has toured the places on your computer where you can use AppleScript. If you're new to AppleScript, you should now be feeling informed and motivated and ready to begin sinking your teeth into some solid facts. If you already have some familiarity with AppleScript, you may be leafing forward through this book, looking for the serious part to begin. Either way, look no further. This is it. The solid, serious stuff starts here.This chapter formally defines and describes AppleScript—what it is, why it exists, where it lives, and how it works—along with all the basic terms and concepts connected with it. Subsequent chapters will provide further details about some of what's here, but they all presuppose the basis laid out in this chapter. Whether you think of it as an introduction, a survey, or a glossary, to understand this chapter is to know AppleScript's world.AppleScript would be pointless without Apple events. Apple events lie at the heart of what AppleScript is, what it does, how it works, and why you're going to use it. From writing more efficient AppleScript code to understanding an application's dictionary, a basic acquaintance with Apple events will help you.A long time ago, in a galaxy far away—actually it was probably in about 1989, in Cupertino, California—some very smart people were completely redesigning and modernizing the Macintosh operating system, creating what was to become System 7 (released in May 1991). And some of these people had a brilliant idea. The system, they decided, should support a messaging system, a way of letting one running application communicate with another. Such communication is called interapplication communication , and the messages sent between applications are called Apple events.There are two parties to an interapplication communication: the application that initiates the message, and the application that receives it. I like to refer to these as theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Apple Events
- InhaltsvorschauAppleScript would be pointless without Apple events. Apple events lie at the heart of what AppleScript is, what it does, how it works, and why you're going to use it. From writing more efficient AppleScript code to understanding an application's dictionary, a basic acquaintance with Apple events will help you.A long time ago, in a galaxy far away—actually it was probably in about 1989, in Cupertino, California—some very smart people were completely redesigning and modernizing the Macintosh operating system, creating what was to become System 7 (released in May 1991). And some of these people had a brilliant idea. The system, they decided, should support a messaging system, a way of letting one running application communicate with another. Such communication is called interapplication communication , and the messages sent between applications are called Apple events.There are two parties to an interapplication communication: the application that initiates the message, and the application that receives it. I like to refer to these as the sender and the target , respectively; 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, with no prior arrangement or synchronization, are suddenly 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, just the opposite, an application can send an Apple event to itself. (Why would it want to do that? You'll find out, in the section "Recordability," later in this chapter.)The breadth of what may be expressed in an Apple event is also quite amazing. Their structure amounts to a remarkably sophisticated grammar: Apple events are like little sentences, possessing (so to speak) verbs and nouns and modifiers, and this grammar is so cleverly and flexibly devised that individual 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." Much of the grammar of the AppleScript language is as it is because of the grammar of Apple events.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- The Open Scripting Architecture
- InhaltsvorschauWhen System 7 was being created, along with Apple events and many other new technologies, it was already Apple's plan to create a language, AppleScript, that would give end users access to the power of Apple events. But, much to the disappointment of users and developers, there wasn't time to create AppleScript before the release of System 7 in mid-1991, and the bulk of the work was postponed until 1992-1993.One of the conundrums facing the founders of AppleScript at this time was the architectural question of where the language should live. They could have made AppleScript the internal scripting language of a single application, like HyperCard's HyperTalk , but this would mean that the user would run AppleScript code entirely from within this one application, which was unacceptable. AppleScript needed to be available everywhere, and thus would somehow have to be part of the system. But what part? There was no good place, so a new one was created: 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.Because 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 a file calledEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Script
- InhaltsvorschauThe word "script," like a number of terms associated with AppleScript, is liable to be tossed rather loosely about in a bewildering variety of senses. Some of its meanings are technically important and therefore indispensable, so it will help if we pause to clarify its chief uses explicitly.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 the Finder should take. This, after all, is why the Finder is said to be "scriptable" in the first place.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:A scripting language is intended for use by both professional and nonprofessional programmers. To accommodate nonprofessional programmers, some aspects of the language may be somewhat less strict.This leap is common enough, but in my view it is unwarranted. Most languages commonly referred to as scripting languages are full-fledged programming languages, and make no particular concession to informality or inexperience. There is arguably nothing easy, and certainly nothing simplistic, about Tcl, Perl, or Scheme. As far as ease of use is concerned, any distinction between a scripting language and a programming language is a distinction without a difference.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Compiling and Decompiling
- InhaltsvorschauTo compile your AppleScript code is a necessary intermediate step between editing it and running it. This section explains what this means, and then discusses some of the implications for you, the AppleScript programmer.To compile code means to transform it from editable text to a form that is understood by some engine that will run the code. The particular form depends upon the nature of the particular engine. At one end of the spectrum, the engine might be the computer's central processing unit (CPU), in which case the code is turned from text to machine-language instructions; that, for example, is how Fortran and C work. At the other end of the spectrum, one can postpone compilation until the program is actually running and a line of code is encountered; for example, in some implementations of BASIC , such as the one that came with the original Apple II, the runtime engine accepts pure text, compiling and executing that text one line at a time. A language that works this way is said to be interpreted.In the early days of computers, most language implementations fell into one camp or the other, being either compiled or interpreted. These days, however, many popular scripting languages (such as Perl, Python, and Java) are implemented through a compromise technique where the entire program is initially compiled into an intermediate representation, which is then fed to a runtime engine that accepts and executes it a chunk at a time. In effect, such languages are compiled, then interpreted. AppleScript works this way.Like those other scripting languages, AppleScript code is compiled into bytecode , meaning that, roughly speaking, the nouns and verbs of the original text are translated into a sort of compressed, coded equivalent, called tokens . These tokens are meaningful to the AppleScript scripting component's runtime engine (and illegible to everyone else). The runtime engine interprets the bytecode, parsing whatever tokens it meets along its path of execution, accumulating them into chunks, and translating these chunks further, as necessary, in order to execute them.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Compiled Script Files
- InhaltsvorschauA compiled script file is just what you think it is: it's a file containing the bytecode of a compiled script. Unlike text, a compiled script file can be executed without being compiled (because it's already compiled); the runtime engine is fed the bytecode and can leap into action immediately. A lengthy script can take several seconds to compile, so a compiled script file clearly saves some time and overhead when the script is executed. Obviously this architecture is advantageous when the script is not going to change and therefore will not need compiling ever again—when you distribute the script to others, for example. Applications that act as script runners typically operate on compiled script files (see "Script Runner" in Chapter 2). Script editor applications save a script as a compiled script file by default. When an application has asked the AppleScript scripting component to compile some text, a compiled script file is the only way for the compiled script to outlive that instance of the AppleScript scripting component, which will go out of existence when the host application quits.(There is actually more to a script, and therefore there can be more to a compiled script file, than the compiled bytecode. I'll discuss these further contents of a compiled script file in "Persistence of Top-Level Entities" in Chapter 8 and "Closures and Stored Script Objects" in Chapter 10.)You cannot save as a compiled script file code that, for whatever reason, will not compile. This seems tautological, but it can be surprising nevertheless, so it is worth mentioning.To make things more complicated, a compiled script file can come in not one, not two, but three different formats :
- Resource-fork file
-
The bytecode is kept in the file's resource fork ; there is no data fork . The type is
'osas'; the extension is .scpt. Historically, this is the oldest form. Script Editor will not create a file in this form (though Script Debugger can), but if Script Editor encounters such a file it can open, edit, and save it in the same form.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Script Text File
- InhaltsvorschauA script text file is exactly that: it's an ordinary text file, such as can be opened by any word processor, consisting of the uncompiled text of your script. Any script editor application will typically offer an option for saving a script as text. No bytecode is saved into the file, and the script need not be capable of compilation in order to be saved as text—as opposed to a compiled script file , which by definition can't be saved unless the script can be compiled. (Apple's Script Editor does also attempt to compile the script when you save it as text, and will report any compilation errors even though saving succeded; this seems like a bug.) The conventional extension for a script text file on Mac OS X is .applescript, but it is still of type
'TEXT'.Most script runners will refuse to execute a script text file; they generally expect a compiled script file, whereas a script text file is not compiled (and the script runner is not willing to do the compilation).A script text file is described by Apple's documentation as a kind of low-grade, last-resort alternative to a compiled script file. But it does have certain advantages. For one thing, obviously, you can save it even though you can't compile the script, so if you're developing a script that won't compile or that you'd rather not compile just now, you have a way to save it. Also there are matters of compatibility and portability. Recall that Apple's Script Editor can't create a compiled script file that will work on early versions of Mac OS 9 or before. And (as I'll discuss later in this chapter) a compiled script file can face difficulties if AppleScript can't locate a needed external referent, which can happen particularly when the script is moved to another computer. A script text file overcomes all these difficulties; it's just text, and therefore is absolutely portable to any machine running any system. Some version of AppleScript and the Script Editor will be present on just about any machine running Mac OS, so the file can be opened and, if the code is valid, the script can be compiled there.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Applet and Droplet
- InhaltsvorschauAn applet is an application with very little graphical user interface, consisting essentially of a compiled script along with a minimal amount of standalone executable code, called the bootstrap code, along with some other resources necessary to make the application scriptable. The bootstrap code, which runs when the applet is launched, simply summons a scripting component called the Script Application Component ; this component does the rest, handing the compiled script over to the AppleScript scripting component for execution, and taking care of such application-like functionality as putting up the applet's menu and its description window if there is one. Thus an applet is a tiny application which, when launched, runs a compiled script embedded within it. A script editor application will allow you to make an applet as simply as saving a compiled script file, just by choosing applet format (called "application") when you save (or choose File → Save As).When you save your script as an application, the script editor application looks to see whether it has an
openhandler. If it does, the application becomes a droplet . A droplet is just like an applet, except that it has a different creator type (the creator type for an applet is'aplt', while for a droplet it's'dplt') and a slightly different icon; functionally, the difference is that a droplet does something when file or folder icons are dropped onto its icon in the Finder. Typically, a droplet responds to the dropped items by processing them in some way (for an example, see "Calculation and Repetition" in Chapter 1). A droplet can also function like an applet: as a droplet, it does something when items are dropped onto its icon, while as an applet, it does something when it is launched from the Finder.An applet's script remains editable unless you save it as run-only . Unlike a compiled script file, you can't edit an applet's script by opening the applet from the Finder, because that launches the applet. Instead, you open it from within a script editor application, using File → Open, or by dropping the applet's icon on the script editor application's icon in the Finder. A running applet may also display some graphical interface offering a chance to edit its script.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Scripting Addition
- InhaltsvorschauAppleScript is a little language, and at a very early stage it was felt to be a bit too little. An architecture was therefore devised whereby Apple, as well as third-party developers, could extend the language by means of scripting additions. A scripting addition is a code library, typically written in a compiled lower-level language such as C, whose purpose is usually to endow AppleScript with 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. On Mac OS 9 and before, a scripting addition is a resource file of type
'osax'; on Mac OS X it can also be a bundle with extension .osax. Therefore it is common parlance to refer to a scripting addition as an osax (official plural, osaxen).When an instance of the AppleScript scripting component comes into existence, it loads any scripting additions found in any of several locations , namely /System/Library/ScriptingAdditions and the corresponding folders in /Library and ~/Library. (On Mac OS 9 and before, there is just one location, the Scripting Additions folder of the System Folder. Observe the lack of a space in the Mac OS X folder name ScriptingAdditions; the tale of how that happened is gory and not to be recounted here, and in any case it's too late now to change it.) If a script depends upon a scripting addition, it is up to the end user to install that scripting addition first on any machine where that script is to run. Unfortunately, end users can't be relied upon to do this, which makes it hard to share your scripts with other users if your scripts depend upon any third-party scripting additions . Fortunately, an applet bundle or an AppleScript Studio application will also load scripting additions contained within its own bundle, an innovation that nicely solves the problem.Tiger comes with just two scripting additions installed by default: StandardAdditions and Digital Hub Scripting . Some earlier systems came with half a dozen scripting additions from Apple, which was confusing; the StandardAdditions osax incorporates most of the functionality of these earlier files.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Dictionary
- InhaltsvorschauAppleScript is a little language. It is also an extensible language. The purpose of AppleScript is to communicate with scriptable applications by means of Apple events; each such application can extend the terminology of the language in its own way, defining a repertory of Apple events to which it is prepared to respond, along with the English-like AppleScript terms to which these Apple events and their various parts correspond. To be scriptable with AppleScript, the application must publish information about this repertory. The mechanism by which this publication takes place is a resource called a dictionary.The AppleScript scripting component uses the dictionary when compiling and decompiling a script, for two purposes:
-
To confirm, at compile time, that the English-like terms used by the AppleScript programmer are legal
-
To translate, at compile time and at decompile time, between English-like terms and Apple event structures
Not only does a scriptable application have a dictionary; a scripting addition does too, and for the very same reasons. (In fact, AppleScript itself has a dictionary.)A dictionary may be expressed in any of three formats :- The 'aete ' resource
-
The
'aete'resource is present in scriptable applications in Mac OS 9 and before, and in Carbon applications in Mac OS X (and optionally in Cocoa applications as well). For information about its format, see:http://developer.apple.com/documentation/mac/IAC/IAC-308.htmlIn Xcode, to see a header file defining some relevant constants, choose File → Open Quickly and enter AEUserTermTypes.h.An'aete'resource may be static or dynamic . AppleScript can read a static'aete'resource directly off the disk; but it has to ask the application for a dynamic
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Missing External Referents
- InhaltsvorschauAppleScript is a little language, leaving it up to externals such as scriptable applications and scripting additions to extend the vocabulary of the language as needed. A consequence of this architecture is that at various crucial moments during the life of a script, such as when it is compiled, decompiled, or executed, AppleScript will look for externals, and may complain if it can't find them. This section talks what happens on these occasions.When a script is compiled, AppleScript needs each application targeted by that script, so that it can obtain its dictionary to verify the legality of the terms the script is using and to translate those terms into Apple events in bytecode. If it can't find a targeted application, it will present a dialog asking you, the human user, to locate it. At this point, one of three things can happen:
- You cancel out of the dialog.
-
The script won't compile.
- You locate the correct application.
-
The script compiles, and is modified to point to the application you nominated.
- You locate some other application.
-
The script won't compile.
What consitutes "the correct application" is any application whose dictionary defines the terminology AppleScript is trying to verify. To see what I mean, let's start with code like this:get disk 1
If that's all your script says, it won't compile at all, because the termdiskisn't part of the AppleScript language. You can use it this way only while targeting a scriptable application that extends the AppleScript language to include a class calleddisk. Now, suppose we pretend there is such an application, making up a name for this application when in fact we have no application by that name. Let's call it NoSuchApp.tell application "NoSuchApp" to get disk 1
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Modes of Scriptability
- InhaltsvorschauAn application is scriptable if it defines a repertory of Apple events to which it is prepared to respond and publishes that repertory as a dictionary. The dictionary should contain terms that expose the application's core functionality (that caveat is intended to handle the case of applications that publish a dictionary but are not in fact scriptable in any meaningful way; see "Is This Application Scriptable?" in Chapter 1).There are two additional modes (or levels, or aspects) whereby an application can be scriptable:
- Recordable
-
An application is recordable if it can generate AppleScript code when the user performs ordinary actions in its graphical user interface. This ability can be useful for helping the programmer learn to script the application. There is no way to find out whether and to what extent an application is recordable, other than by trying to record it.
- Attachable
-
The term attachable is somewhat ambiguously defined. Strictly, an attachable application is one that allows the user to customize, by means of a script, what happens when the application receives an Apple event. But it may also be said that an application that allows the user to customize any of its event responses through a script is attachable.
As an example of a recordable application, let's take BBEdit. In a script editor application such as Script Editor or Script Debugger, make a new script window, and choose Script → Record (or press the Record button). In BBEdit, press ⌘-N to make a new window. Back in the script editor application, choose Script → Stop (or press the Stop button). In the the script window, the following compiled script has appeared:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 4: Introducing the Language
- InhaltsvorschauPart I of this book describes AppleScript as a technology—why and where and how you use it (Chapter 1 and Chapter 2), the Apple events that lie behind it, the AppleScript scripting component that implements it, the kinds of file it creates and some of the details of working with those files, and the means and modes whereby applications make themselves scriptable with it (Chapter 3). But AppleScript is also a language, a programming language that you'll want to learn and understand in order to create and edit AppleScript code on your own. Part II of this book teaches it to you.This chapter serves as a starting point for your journey through the AppleScript language. The longest journey, it is said, begins with a single step. But even before that, sometimes it's a good idea to contemplate the road. That's what this chapter does. It describes the nature of the AppleScript language in very general terms. What sort of language is it? What is it like to learn and to use?The AppleScript language deserves contemplation, and often gets it. AppleScript's users seem to spend as much time and energy venting their feelings about AppleScript as they do writing and editing AppleScript code. It's that kind of language. It frequently evokes an emotional reaction, and that emotion can range from frustration through exasperation to fury. Yet at the same time AppleScript has some surprisingly clever behaviors and abilities, and some remarkably sophisticated features.I've never created a computer language, but I suspect it must be a special sort of labor, both satisfying and frustrating, a blend of artistry and engineering, calling for vision, philosophy, planning, determination, sweat, time, and sheer technological expertise. A computer is just a machine, but a computer language is a human creation. You might expect it to be dry, cold, and logical, but it isn't. Every computer language bears the stamp of its makers, and to learn a computer language is to experience, in some measure, the forces and ideas and goals that went into its creation. In short, AppleScript has a flavor. This chapter tries to describe that flavor.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- A Little Language
- InhaltsvorschauThe "little language" philosophy, as represented by such computer languages as LOGO, Smalltalk, and Scheme, comes in various forms but the very words "little language" tell you most of what you need to know. Littleness can be a virtue in a number of ways. A little computer language can fit in a small space and be run by a small interpreter. A little computer language can be easy to learn, just because there's less of it to learn. A computer language is a tool to make tools, so the initial tool itself can be quite minimal, provided it has the power to make any other tools that may prove necessary.All of these notions apply to AppleScript. AppleScript was to be easy for users to learn, so the less there was of it, the better. AppleScript appeared at a time when the idea of a computer with as much as four megabytes of random-access memory still felt rather strange and extravagant. To minimize expenditure of time and space resources, it had to compile with just a single pass. In these days of hundreds of megabytes of RAM and dozens of processes running simultaneously, it's easy to forget that AppleScript comes from a day when running more than one application at once on your Macintosh was a relatively new experience, and liable to tax the computer's resources to the utmost. At the time, AppleScript itself needed to be small simply to stay out of the way of other applications. The first version of AppleScript could load a scripting component instance and run a heavily recursive script in less than 300K of RAM.And the purpose of AppleScript, after all, was to tell other programs to do things. Thus AppleScript itself could afford to be so minimal as to have little or no power of its own. AppleScript has minimal string-munging and number-crunching facilities, but then AppleScript is not intended for munging strings or crunching numbers—it's made for driving applications, and they can munge the strings and crunch the numbers if need be.So is AppleScript's littleness a virtue? Probably not—at least, not any more. Thanks to Moore's Law and the passage of time, we no longer need AppleScript to be so tiny. Its small size certainly makes it easier to learn than, say, Perl (a language so big and so full of options and functions it can make your head swim), but it is not an easy language at all; on the contrary, it's tricky and quirky and needs a big book like this one to explain it. And if you're used to a full-fledged scripting language, AppleScript comes as something of a disappointment. Perl, for example, has some hundreds of built-in functions; AppleScript has about a dozen, and seems to be missing some extremely basic functionality. Perl has built-in support for powerful string manipulation, regular expressions, and trigonometry; AppleScript doesn't. Just as you don't miss the water until the well runs dry, the "little language" philosophy seems very cute just until you actually need to get something done. On the other hand, if you don't try to misuse it, AppleScript seems quite adequate, especially since it can now (under Mac OS X) avail itself directly of the power of Perl and other built-in Unix tools. As I said in Chapter 1, success may be simply a question of combining specialities appropriately.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Extensibility and Its Perils
- InhaltsvorschauAs part and parcel of its power to communicate with other applications, AppleScript concedes to those applications an ability to extend the language. Such linguistic extensions appear temporarily to be part of AppleScript, only while your program is talking to the application that provides them. We thus have a language that grows and shrinks and mutates depending on what application it is talking to. For example, AppleScript itself knows nothing of a disk or a folder, but the Finder does. So as long as your AppleScript code is talking to the Finder, it can speak of a disk or a folder. The moment it is no longer talking to the Finder, it can't.This architecture, as we saw in Chapter 3, has its practical consequences. An AppleScript program that talks to a particular application can be severely hampered by the absence of that application. Even if you know all about BBEdit and how it extends the AppleScript language, you can't compile a script that talks to BBEdit unless you have BBEdit present on your machine at the time. If you send your friend a compiled script file that talks to BBEdit and your friend doesn't have BBEdit, your friend can't even read the script, let alone run it.For the programmer, the main consequence of AppleScript's extensibility is that it is not one language but many—as many as there are applications to which you might wish to speak. (You can see this consequence in action in Appendix A, where all my knowledge of AppleScript is as nothing compared to my ignorance of how to talk to one particular application.) Thus the AppleScript programmer, no matter how expert, remains something of a perpetual neophyte. Even the most AppleScript-savvy programmer I know has said to me, "I hate trying to figure out the scripting quirks of every app." AppleScript thus displays some tendency to discourage its most devoted users from doing the very thing it was intended to do.Perhaps even worse than all of this is the everlasting conflict between the various namespaces: terms in a target application, terms in scripting additions, terms in AppleScript itself, and terms you make up for your own use. You just never know when you'll try to say something in AppleScript and it will fail at compile time or at runtime with a mysterious error message, all because an already defined term of whose existence you had no inkling or warning has stepped on your toes. I've mentioned this before ("Dictionary" in Chapter 3) and I'll talk at length about it again ("Terminology Clash" in Chapter 20).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- The "English-likeness" Monster
- InhaltsvorschauAs we have already seen, AppleScript is English-like. Its vocabulary appears to be made up of English imperative verbs, nouns, prepositional phrases, and even an occasional relative clause.Whether this English-likeness is a good thing is debatable. It is probably responsible for attracting users who would otherwise be frightened by the rigid-looking pseudo-mathematical terseness of a language like Perl, with its funny variable names, its braces and brackets and semicolons and other impenetrable punctuation. Personally, though, I'm not fond of AppleScript's English-likeness. For one thing, I feel it is misleading. It gives one the sense that one just knows AppleScript because one knows English, but that is not so. It also gives one the sense that AppleScript is highly flexible and accepting of commands expressed just however one cares to phrase them, and that is really not so. This sense is reinforced by AppleScript's abundance of synonyms. For example, instead of saying:
if x <= y
you can say:if x is less than or equal to y
You are also allowed to use the word "the" wherever it feels natural. And nouns even come with plurals:get the first word of "hello there" get the words of "hello there"
Nevertheless, none of this is due to AppleScript's knowing any English. AppleScript actually has no natural language intelligence at all. AppleScript is every bit as mathematically structured, rigid, and unforgiving as Perl or any other computer language. If you step outside its rules by a tiny fraction of an inch, AppleScript slaps your hand just as any computer language would. The trouble here, I suggest, is that it was AppleScript's similarity to English that tempted you (subconsciously perhaps) to break the rules in the first place.For example, later in the book I will have to leap up and down and wave my arms wildly to warn the reader not to confuse these two constructs:get words 1 thru 4 of "now is the winter of our discontent" get text from word 1 to word 4 of "now is the winter of our discontent"
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Object-likeness
- InhaltsvorschauIn many computer languages, values are things that you talk about. In AppleScript, values are things that you talk to. The following is a legal way (though no one in his right mind would actually talk like this) to add 4 and 5 in AppleScript:
tell 4 get it + 5 end tellThe use oftell(we are addressing the number 4),get(we are ordering the number 4 about), andit(which means "whoever I am now addressing") shows the nature of the idiom. To be sure, one can (and will) add 4 and 5 by saying something much simpler:4 + 5
Yet this second way of talking works only because, behind the scenes, AppleScript is supplying thetelland thegetfor you, to make your life simpler. In AppleScript, whether you know it or not, you are always talking to some value and telling it to do something.One might therefore suppose that AppleScript is an object-oriented language and that all values in AppleScript are objects. Perhaps, one thinks, AppleScript will turn out to be like Smalltalk, where "everything is an object." AppleScript also has certain values that are explicitly called "objects," and refers to the datatypes of all values as "classes." Plus, in a couple of areas AppleScript implements a kind of "inheritance" between one object (or class) and another. All of these things add to the impression that AppleScript might be object-oriented. Plus, Apple's own documentation states flatly that it is.Nonetheless, I remain skeptical. I don't think AppleScript is really object-oriented or even object-based. I've come to think of AppleScript as merely having values with certain object-like aspects. Perhaps the reason for the object-likeness of AppleScript's values has something to do with the fact that AppleScript is all about sending messages (Apple events) to scriptable applications (see "Apple Events" in Chapter 3). Having devised a syntax for representing this message-sending architecture in an English-like way, AppleScript's inventors seem to have generalized this syntax to pervade the language.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - LISP-likeness
- InhaltsvorschauA number of features of AppleScript seem to suggest that someone on the original AppleScript team was devoted to LISP, or to some LISP dialect such as Scheme. As I myself am fond of Scheme, I rather like these features.For example, AppleScript has lists, which are ordered collections of any values whatsoever. It provides certain primitive operations for dealing with these lists, such as taking the first element, taking everything but the first element, and joining two lists into one (like Scheme 's
car,cdr, andcons). And AppleScript permits recursion (a subroutine calling itself).Thus, it is possible to write AppleScript code that bears an extraordinary resemblance to Scheme code. To give an example, here's a little Scheme program that defines a routine for removing the nth element from a list, and then tests the routine:(define remvix (lambda (ix ls) (cond ((null? ls) '( )) ((= ix 1) (cdr ls)) (else (cons (car ls) (remvix (- ix 1) (cdr ls))))))) (remvix 2 '(mannie moe jack))And here's the same thing done in just the same style in AppleScript:on remvix(ix, ls) if ls is {} then return {} else if ix is 1 then return rest of ls else return {item 1 of ls} & remvix(ix - 1, rest of ls) end if end remvix remvix(2, {"Mannie", "Moe", "Jack"})Even if you don't know any Scheme or any AppleScript, the structural and stylistic similarity of these approaches is unmistakeable; they are in fact move-for-move identical, the only differences between them being matters of syntactic detail. To be sure, I've stacked the deck by deliberately writing the AppleScript routine in a Scheme-like style; but the point is that AppleScript is capable of that style, and invites it.AppleScript also can generate closures (subroutines that remember their global environment). And there is a sense in which all the components of a script—variables, handlers, and script objects—possess the same first-class status; for example, any of them can be passed as a parameter to, or returned as a result from, a subroutine. All of this has a markedly LISP -like flavor.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The Learning Curve
- InhaltsvorschauIn this chapter I've argued that AppleScript isn't easy just because it's small or just because it's English-like, and I've mentioned that AppleScript borrows some features from object-oriented languages and LISP that you may never have heard of and whose mere mention may have made your eyes glaze over. So perhaps at this point you're starting to worry that AppleScript is difficult to learn. But that isn't what I mean either! What I'm telling you is that AppleScript is a computer language, like any other computer language. You weren't born knowing it, and you aren't going to be able to use it without learning it. And, thanks to this book, you will learn it. AppleScript is a straightforward computer language, and can be taught and learned in a straightforward manner; if I didn't believe that, this book wouldn't exist.AppleScript is extensible, so this book will tell you how to read a scriptable application's dictionary, warn of possible pitfalls, and give plenty of examples. AppleScript is English-like, so the book will teach a clean, concise style, and will wave a red flag when an analogy with natural language threatens to mislead. AppleScript values are object-like; this book tells you how to talk to them. AppleScript has some LISP-like features; this book elicits these features where they are relevant, but where they seem too advanced, you can always skip a section and return to it later on. If this book occasionally comments on the odd way AppleScript does certain things, it is not to frighten or frustrate the reader, but rather to gain the reader's trust. It's just my way of saying, "Don't worry if this seems weird; it is weird."So approach AppleScript without fear. It deserves respect, appreciation, and perhaps a little wonder. After all, it's amazingly old. Thanks to the Mac OS X revolution, Apple has thoroughly modernized a system that was breaking under its own accumulated weight of years; yet AppleScript remains, to all intents and purposes, its same old self. The fact that AppleScript works at all in this brave new world of Unicode text and POSIX paths is simply amazing. But it does, and until a new broom comes along to sweep it clean, having to negotiate some accumulated quirks and cobwebs dating from the creation seems a small price to pay.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Chapter 5: Syntactic Ground of Being
- InhaltsvorschauThis chapter is about the basic facts of AppleScript language syntax. These are the facts you must be aware of before you can read or write any AppleScript code at all.AppleScript is a line-based language. There is no visible command terminator, such as a semicolon; a command ends with and is separated from the next command by a line break. For example:
set x to 1 copy x + 1 to y display dialog y
You can't have one complete command and then another complete command in the same line, but you can have one command nested inside another command, because most commands in AppleScript have a result (see "Result," later in this chapter), and most commands have at least one parameter, so the result from one command can often be used as the parameter to another command, in the same line. So, for example, in the second line of this code:set x to 1 copy (display dialog x) to y
The only commands that can't be nested inside other commands in this way are a few special verbs implemented deep inside AppleScript, such assetandcopy.It is legal for a line to be completely blank. Extra whitespace (spaces, tab characters) is legal and will be ignored.In a decompiled script, the breaks between lines are all Macintosh return characters (\r, ASCII character 13). This is somewhat ironic, because in a present-day script editor application such as Script Editor or Script Debugger, when you press the Return key what you're entering is a Unix newline (\n, ASCII character 10). Thus the line-termination character goes into the compiler as a Unix line break and comes back out on decompilation as a Macintosh line break.Indeed, in a script text file (or other text to be treated as AppleScript code) it doesn't matter whether the line-break character is the Macintosh line break, the Unix line break, or even the Windows line break (\r\n). If the code is valid, AppleScript will be able to compile it regardless (and all the breaks between lines of code will end up as Macintosh line breaks internally).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Lines
- InhaltsvorschauAppleScript is a line-based language. There is no visible command terminator, such as a semicolon; a command ends with and is separated from the next command by a line break. For example:
set x to 1 copy x + 1 to y display dialog y
You can't have one complete command and then another complete command in the same line, but you can have one command nested inside another command, because most commands in AppleScript have a result (see "Result," later in this chapter), and most commands have at least one parameter, so the result from one command can often be used as the parameter to another command, in the same line. So, for example, in the second line of this code:set x to 1 copy (display dialog x) to y
The only commands that can't be nested inside other commands in this way are a few special verbs implemented deep inside AppleScript, such assetandcopy.It is legal for a line to be completely blank. Extra whitespace (spaces, tab characters) is legal and will be ignored.In a decompiled script, the breaks between lines are all Macintosh return characters (\r, ASCII character 13). This is somewhat ironic, because in a present-day script editor application such as Script Editor or Script Debugger, when you press the Return key what you're entering is a Unix newline (\n, ASCII character 10). Thus the line-termination character goes into the compiler as a Unix line break and comes back out on decompilation as a Macintosh line break.Indeed, in a script text file (or other text to be treated as AppleScript code) it doesn't matter whether the line-break character is the Macintosh line break, the Unix line break, or even the Windows line break (\r\n). If the code is valid, AppleScript will be able to compile it regardless (and all the breaks between lines of code will end up as Macintosh line breaks internally).It is legal to type a line break in a literal string (that is, between matched pairs of double quotes). This represents a line-break character within the string. For example:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Result
- InhaltsvorschauAt runtime, a line of AppleScript code that actually executes an expression—that is, it isn't blank, a comment, or mere flow control (looping and branching)—will usually generate a result . This result is some sort of value; the particular value depends upon what the line does.The line need not be a command; any valid AppleScript expression constitutes a valid line, even if it does nothing. For example, this is a valid line of AppleScript code, and it has a value (can you guess what it is?):
5
A line's result may be captured in two ways: explicitly or implicitly. The next two sections describe them both. As you'll see, my view is that in general you should not make any use of the fact that a line of code has a result. However, the exception proves the rule, so I will also suggest that in just one situation (while developing your code) capturing a line's value implicitly is useful.The result of a line after it is executed may be captured explicitly by using the keywordresultin the next line that is executed. For example:5 display dialog result 5One sees this technique used typically after fetching a value in a context of interapplication communication. For example, this is a fairly common style of coding:tell application "Finder" get the name of every folder end tell set L to the resultHere's another example:tell application "Finder" count folders end tell set c to the resultWhy is this technique so common? It may be a habit derived from HyperTalk , where this was a standard idiom. Or people may feel that a line is more legible and understandable if it consists of a single command. Nonetheless, this technique is unnecessary. You can execute a command and capture its result in the same line by nesting commands, as I mentioned in the previous section:tell application "Finder" set L to (get the name of every folder) set c to count folders end tellEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Comments
- InhaltsvorschauAppleScript permits two kinds of comment : single-line comments and delimited comments. Everything including and after two successive hyphens on a line is a single-line comment. For example:
set a to 1 -- this a comment on the same line as a command -- this a comment on a line by itself
The comment delimiters are(*and*). Everything between comment delimiters is a comment. Such a comment may span multiple lines. This code contains three stretches of text that are legally commented out with comment delimiters:set a to 1 (* because we feel like it; tomorrow we may not feel like setting a to 1 *) (* in fact things could be very different tomorrow, but I really can't speak to that issue just now *) set b to 2 (* this seems a good idea too *)
A comment delimited with comment delimiters may not interrupt a command, nor precede a command on the same line. Neither of these lines will compile:set a to (* because we feel like it *) 1 (* here's a good idea *) set a to 1
Comment delimiters attempt to be "intelligent." Comments may be nested, in which case the delimiters must match in pairs. Thanks to this rule, you can easily comment out a stretch of script that already contains some comments:(* outer comment (* inner comment *) rest of outer comment *)
A rather weird side effect of this "intelligence" is that quotation marks and vertical bars inside comment delimiters must also match in pairs:(* "this works fine" and so does |this| *)
If you remove one quotation mark or one vertical bar from inside that comment, the code won't compile.Single-line comments take precedence over everything (they cause the rest of the line to be ignored, with no attempt at "intelligence"). Thanks to this rule, you can easily comment out comment delimiters. You might wish to do this while testing, as a quick way of effectively removing and restoring some code. Here, the line of code is commented out and is not executed:(* set a to 7 *)
Here, the comment delimiters are commented out, so the line of codeEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Abbreviations and Synonyms
- InhaltsvorschauMany AppleScript terms permit other terms to be substituted for them. For example, the following expressions are equivalent in pairs, assuming that
aandbare defined:a is less than b a < b a is b a = b
Some terms have a very large number of equivalents. For example, these expressions all amount to the same thing:a ≤ b a <= b a less than or equal b a is less than or equal to b a is not greater than b a isn't greater than b a does not come after b a doesn't come after b
To add to the confusion, upon decompilation, AppleScript might substitute one equivalent for another (see "Decompiling" in Chapter 3). So the code in the previous example compiles, but afterwards it looks like this:a ≤ b a ≤ b a is less than or equal to b a is less than or equal to b a is not greater than b a is not greater than b a does not come after b a does not come after b
I call terms that are functionally equivalent to one another synonyms . I call terms that are replaced by other terms on decompilation abbreviations .Code in this book is compiled before being pasted into the page, so you won't see any abbreviations in the book's code examples (except, as here, with the explicit purpose of displaying an abbreviation). In fact, this book does not even list abbreviations, except where I find them particularly handy when typing code. For example, in real life I never type the wordapplicationbecause I know the abbreviationappwill do; so I tell you about this abbreviation ("Application" in Chapter 13).I don't tell you about all synonyms either, and on the whole I try not to use them. I feel that it's good style, and makes your AppleScript code more legible, to adopt just one synonym for each term and stick with it. In general my personal preference is the shortest synonym, but not always; for example, of the following two expressions, I prefer the second:a ≠ b a is not b
And in a very small number of cases I do use two synonyms indiscriminately. For example, I'm equally likely to use either of these expressions:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Blocks
- InhaltsvorschauA block is one or more lines of code demarcated from its surroundings as having a separate nature or purpose. A block is announced by a line stating what type of block it is; then comes the code of the block; and finally the block is terminated by a line starting with the keyword
end. Blocks can occur within blocks.It's very easy to spot a block in AppleScript code, because in decompiled code its lines are indented from the announcement line and the termination line. For example:myHandler( ) on myHandler( ) repeat 3 times display dialog "Howdy" end repeat end myHandlerThat code contains two blocks. One is announced with theon myHandlerline, and is terminated by theend myHandlerline; everything in between them is the code of that block. That code consists of another block, announced with therepeatline and terminated by theend repeatline; the line of code in between them is the code of that block.In this book I frequently refer to such blocks by their announcement keyword; for example, I might say "a repeat block."Some blocks (just two, actually—tell blocks and if blocks) have single-line variants. This permits some rather twisted condensed syntax. For example:tell application "Finder" if exists folder "Mannie" then reveal folder "Mannie" end if end tellYou can reduce one or both of those blocks to a single line. So, this is legal (but I never talk this way, and I don't recommend you do either):tell application "Finder" to if exists folder "Mannie" then reveal folder "Mannie" end ifWhen typing a block, don't bother to type the name of the block a second time in theendline. Just typeendfor that line; the compiler will fill in the name of the block. (For example, don't typeend repeat; just typeend, on a line by itself, and the compiler will see that this corresponds to a precedingrepeatline and will fill in the fullend repeatfor you.) This is not just a time-saving device; it's also a way to ensure that your blocks are structured correctly.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The
- InhaltsvorschauAppleScript allows you to use the word
thebefore almost anything. This is pure syntactic sugar, and I never use it. For example, this is perfectly legal:set the x to the 9 display dialog the (get the the the the x + the 1)
Now, really.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 6: A Map of the World
- InhaltsvorschauEvery AppleScript program is a script. This chapter describes the structure of a script. A script is composed of certain definite building blocks, and they go together in a certain way. The next several chapters will return to each of these building blocks individually and explain them in full detail, but first we need an introduction to the entire cast of characters that constitute a script. That's what this chapter is for. It provides the crucial overall map of a script's world, so that in our explorations during subsequent chapters you'll know where we're going and how the geography fits together.Recall (from "Blocks" in Chapter 5) that a pretty-printed script displays its structure by means of indentation. Every set of indented lines is introduced by an
online and terminated by a correspondingendline. The whole thing is a block . For example, this is a repeat block:repeat 3 times display dialog "Howdy" end repeatIt turns out that two types of block are very special in AppleScript: a script object definition and a handler definition. They are special in many ways. These are the only blocks that function as what I'll call top-level entities in a script. They are not merely blocks; they are also variable definitions. There are special rules for where they occur in a script. Most obviously, they are the regions of scope in a script; for this reason, I call them the scope blocks.Scope will be fully discussed in Chapter 10, but the idea is very simple. Some parts of a script are divided off from other parts by a kind of magic wall of impenetrability. Even if the parts can see each other, they cannot necessarily see inside one another. The word scope is the technical term for the visibility of part of a script: the scope of a thing is precisely equivalent to the rules for what parts of a script can see that thing. A script object definition and a handler definition are the only two kinds of block with the ability to put up these walls. They delimit—and in essence, are—the regions of scope within a script, the regions that are divided from one another by special rules as to who can see what. No other blocks have this magic power.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Scope Blocks
- InhaltsvorschauRecall (from "Blocks" in Chapter 5) that a pretty-printed script displays its structure by means of indentation. Every set of indented lines is introduced by an
online and terminated by a correspondingendline. The whole thing is a block . For example, this is a repeat block:repeat 3 times display dialog "Howdy" end repeatIt turns out that two types of block are very special in AppleScript: a script object definition and a handler definition. They are special in many ways. These are the only blocks that function as what I'll call top-level entities in a script. They are not merely blocks; they are also variable definitions. There are special rules for where they occur in a script. Most obviously, they are the regions of scope in a script; for this reason, I call them the scope blocks.Scope will be fully discussed in Chapter 10, but the idea is very simple. Some parts of a script are divided off from other parts by a kind of magic wall of impenetrability. Even if the parts can see each other, they cannot necessarily see inside one another. The word scope is the technical term for the visibility of part of a script: the scope of a thing is precisely equivalent to the rules for what parts of a script can see that thing. A script object definition and a handler definition are the only two kinds of block with the ability to put up these walls. They delimit—and in essence, are—the regions of scope within a script, the regions that are divided from one another by special rules as to who can see what. No other blocks have this magic power.So what do they look like, these two special types of block? That's very simple. A script object definition is a block announced by the keywordscript:script scriptName -- commands within the script object end script
A handler definition is a block announed by the keyboardon:on handlerName( ) -- commands within the handler end handlerName
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Levels and Nesting
- InhaltsvorschauLooking at how blocks are indented, we can think of them as arranged in levels. For example, in this code the
ifblock is one level down from theonblock (the handler definition), and therepeatblock is two levels down from theonblock:on myHandler( ) if weekday of (get current date) is Monday then repeat 3 times display dialog "Howdy" end repeat end if end myHandlerCode that occurs directly inside a block may be said to be at the top level of that block. In the preceding code, theifblock is at the top level of the handler.Of course, what's at the top level of a block needn't be another block. So in the preceding code, thedisplay dialogcommand is at the top level of therepeatblock. But when a block is at the top level of another block, we can describe the two blocks in relation to one another as nested. So in the preceding code, therepeatblock is nested in theifblock, and theifblock is nested in the handler.Most blocks can just be nested in one another indiscriminately. But the rules for nesting handler and script object definitions are special (and this is part of what makes them special types of block, and why they are the subject of this chapter). In particular, there's a special rule for where a handler definition can appear:A handler may be defined only at the top level of a script object (or of a script as a whole ).
This rule is enforced by the AppleScript compiler. So, this code won't compile:repeat 3 times on sayHowdy( ) display dialog "howdy" end sayHowdy end repeat -- compile-time error: Expected "end" but found "on"The rule also means, obviously, that you can't nest a handler directly within a handler. This code won't compile:on outer( ) on sayHowdy( ) display dialog "howdy" end sayHowdy end outer -- compile-time error: Expected "end" but found "on"But there's a way out of these limitations. A script object definition can appear anywhere. So to define a handler in a handler, define it in a script object in a handler:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The Top Level
- InhaltsvorschauThe top level of all is the script as a whole. (Okay, I lied. There are actually some secret levels even higher than that. But just pretend, for now, that there aren't.) What's more, the script as a whole is itself a script object, even though it has no name and is not defined by a block.This strange-sounding fact is actually extremely cool. It gives your script a sort of overall uniformity. For example, a handler definition can't occur anywhere except at the top level of a script object. So why is it possible for this to be a script?
on sayHowdy( ) display dialog "howdy" end sayHowdy sayHowdy( )There's a handler definition sitting there, not nested in a script block. But that doesn't break the rule; it accords with it, because the script as a whole is itself a script object, so this handler definition is in fact at the top level of a script object, precisely where it should be.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Code and the Run Handler
- InhaltsvorschauSo far, we've talked about blocks, and in particular about script object and handler definitions, as the constituents of a script. But of course there's more to a script than that: there's the actual code, the commands, the stuff that does something. From a visual point of view, code can appear anywhere. But wherever code appears, if you work your way up the levels of nesting, sooner or later you'll always come to either a handler or a script object. That's what the code is really inside of.For example:
set x to 1 on outer( ) set xx to 1 script s set xxx to 1 on sayHowdy( ) display dialog "howdy" end sayHowdy set xxxx to 1 end script set xxxxx to 1 end outer set xxxxxx to 1That script is exactly the same as an earlier example, except that I've added code lines, so that given the structure of the script (a handler in a script object in a handler), at least one line of code appears in every place where code can possibly appear. All the lines of code aresetcommands, except for thedisplay dialogcommand in the middle. So now consider the line "set xx to 1." Where is it, structurally? It's inside the handlerouter. You can do this for every line of code.This little game is significant because the regions demarcated by the handler and script object definitions are also regions of scope. The line "set xx to 1" talks about a variable calledxx. Because of how and where this line occurs, there are strict rules about what parts of the script can and can't see this variablexx. (Those are the rules I'll talk about in Chapter 10.)Now, here's a curious fact. Strictly speaking, code doesn't occur just anywhere. Code can occur only in a handler. Once again, this may sound weird, but it is actually very elegant, because it makes the structure of a script nice and uniform. There's just one problem: it looks like I must be lying. Surely the first line of the script, "set x to 1," is not in a handler, right? It's in a script object, because it's at the top level of the script and the script as a whole is itself a script object . Similarly, the line "set xxx to 1" is at the top level of a script object, and not in a handler. Right?Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Variables
- InhaltsvorschauTo complete our map of the world of a script, we must include variables. A variable is an association (formally, a binding) between a name and a value. You can think of it as a shoebox with a label on it, into which something is placed for storage. The shoebox's label is the variable's name; what's inside the shoebox is the variable's value. For example, when we say:
set x to 5
it is as if we had a shoebox labeled "x" into which we place the number 5.Naturally, variables are very useful things, which is why just about all computer languages have them. To be able to assign your own names to things makes your program clearer and easier to maintain. And in a way any computer program is all about manipulating values, so it's nice to have a place to put each value when you're not using it, so that you can retrieve it again later. A variable's value is like the coffee in your cup when you set the cup on the table, do something else, and then pick up the cup and take a sip. The cup is like the variable; without it, the coffee would just flow onto the floor when you're not using it.Variables and code are intimately related. Code is where variables are defined; code is where variables are given their values and where those values are retrieved.Variables and scope blocks (handler definitions and script object definitions) are intimately related. Variables are what scope is all about: they are the "things" that other regions of the code either can or can't see, depending on the rules of scope, the location of the code, and the nature of the walls constructed by the scope blocks. In fact, we can go even further and say that every variable "lives" at the top level of a handler or a script object (and those are the only places where a variable can "live"). In fact, we can go even further than that: handlers and script objects live at the top level of a script object too, and this is because handlers and script objects are themselves variable values. This may sound confusing right now, but after you've read a few more chapters, it will all seem perfectly natural.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 7: Variables
- InhaltsvorschauThis chapter describes the rules for assignment , declaration, typing, initialization, and naming of variables in the AppleScript language.If a variable is a labelled shoebox (see "Variables" in Chapter 6), then to assign a value to a variable is to put something into the shoebox. If the variable already has a value, that value is replaced.Assignment is performed with one of two commands:
setorcopy.setSyntaxset variableName to value
DescriptionAssigns value to variableName.Exampleset x to 5
There is a synonym using the wordreturninginstead ofset, with the parameters in reverse order, like this:5 returning x. But I have never seen this synonym used.copySyntaxcopy value to variableName
DescriptionAssigns value to variableName.Examplecopy 5 to x
An abbreviation forcopyisput; an abbreviation fortoisinto. Thus you could typeput 5 into x—although it would still come out ascopy 5 to x. These abbreviations were designed to accommodate HyperCard users, who were habituated to this idiom.There is no simple assignment operator, such as the equals sign (=). You cannot, for example, perform an assignment like this:x = 5
That is a comparison, and returns a boolean result revealing whetherxis already 5. That code is legal (and therefore does not cause a compile-time error) but is not an assignment (as any mildly experienced programmer would expect); this is a frequent cause of bugs in my scripts. See "The "English-likeness" Monster" in Chapter 4.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Assignment and Retrieval
- InhaltsvorschauIf a variable is a labelled shoebox (see "Variables" in Chapter 6), then to assign a value to a variable is to put something into the shoebox. If the variable already has a value, that value is replaced.Assignment is performed with one of two commands:
setorcopy.setSyntaxset variableName to value
DescriptionAssigns value to variableName.Exampleset x to 5
There is a synonym using the wordreturninginstead ofset, with the parameters in reverse order, like this:5 returning x. But I have never seen this synonym used.copySyntaxcopy value to variableName
DescriptionAssigns value to variableName.Examplecopy 5 to x
An abbreviation forcopyisput; an abbreviation fortoisinto. Thus you could typeput 5 into x—although it would still come out ascopy 5 to x. These abbreviations were designed to accommodate HyperCard users, who were habituated to this idiom.There is no simple assignment operator, such as the equals sign (=). You cannot, for example, perform an assignment like this:x = 5
That is a comparison, and returns a boolean result revealing whetherxis already 5. That code is legal (and therefore does not cause a compile-time error) but is not an assignment (as any mildly experienced programmer would expect); this is a frequent cause of bugs in my scripts. See "The "English-likeness" Monster" in Chapter 4.As they both perform assignment, you might thinkEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Declaration and Definition of Variables
- InhaltsvorschauThere is no requirement in AppleScript that variables be declared explicitly. The rule is basically that if you use a word that AppleScript doesn't understand, the word is assumed to be the name of a variable. The following code, as a complete script, will compile just fine:
set x to x + 1
Although it is not necessary to declare a variable, it is possible to declare a variable. I'll explain how you do this, and argue that there are good reasons for doing it, in Chapter 10.The code in that last example, as a complete script, will compile, but it won't run; at runtime, it generates an error. The error message reads: "The variable x is not defined." The problem is not that the variablexhas never been declared! There is no need to declare it. AppleScript understands (or assumes) thatxis supposed to be a variable. Nor is the problem that you are trying to assign to it. The problem is that you are trying to fetch its value, and it has no value. That's becausexhas never been assigned a value. An AppleScript variable is not defined until you first explicitly give it a value. To continue our shoebox analogy, there is no "x" shoebox to fetch the contents of, because you've never put anything into it.This code both compiles and runs:set x to 5 set x to x + 1
During execution of the first line, AppleScript observes that you're putting something into the "x" shoebox, but there is no such shoebox as yet. No problem; AppleScript creates the shoebox, labels it "x", and puts 5 into it. Now the second line runs fine, because there is a shoebox "x" from which to fetch a value.Once a variable has been defined, it generally stays defined until its scope finishes executing. There is no command explicitly letting you "undefine " a variable or assign the "undefined" value to it. There are a couple of constants, such asnullandmissing value, that you can assign as a sort of placeholder to signify that a variable hasn't been assigned any other value (see Chapter 17). However, you can in fact genuinely undefine a variable by assigning to it the result of a command that has no result. This is typically an accident: you were expecting a command to return a value, but it doesn't. Code for doing it on purpose appears under "Returned Value" in Chapter 9.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Variable Names
- InhaltsvorschauThe name of a variable must begin with a letter or underscore and must consist entirely of alphanumeric or underscore characters. So a variable name must begin with a character in the character set
[a-zA-Z_]and must consist entirely of characters in the character set[a-zA-Z0-9_].Variable names are case-insensitive at compile time. That means the following code will compile and run:set myVar to 5 set myvar to myvar + 1
AppleScript assumes thatmyvarin the second line is the same variable asmyVarin the first line. Furthermore, as a reflection of this assumption, AppleScript rewrites the variable names after compilation (that is, during decompilation) so that their case matches the first usage of the name:set myVar to 5 set myVar to myVar + 1
This phenomenon suggests a trick that can help you spot mistakes: when you first define a variable, use an uppercase letter in its letter; elsewhere, never use an uppercase letter in a variable name. Then, after compilation, any variable name without an uppercase letter must be a mistake. For example, here's some code that I typed following these rules, before compilation:set myVar to 5 set mybar to myvar + 1
Here's the same code after compilation:set myVar to 5 set mybar to myVar + 1
In that code I have accidentally created and set the value of an unwanted variablemybarin the last line. I meant to saymyvar, but I mistyped it. This won't cause AppleScript to generate any error, and the script will misbehave. The chances that I will spot my mistake are increased by my use of the case trick.But this trick is not easy to implement, and it's unreliable because you still might not spot the mistake. The truth is that incorrect variable names are a notorious cause of bugs in scripts, and can be extremely difficult to track down. The real problem is that AppleScript doesn't require you to declare your variables (and unlike Perl with itsstrictmode, it doesn't let you require it to require you). In my view, this is one of many instances where a feature probably intended to make the language easier actually makes it harder.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 8: Script Objects
- InhaltsvorschauA script object is a script within a script. In fact, a script really is a script object, though it also has a special status as the top-level script object. Script objects have certain remarkable features. They have variables of a special kind—I call these top-level entities—that belong to the script object, but can be retrieved and assigned to from elsewhere. They have a run handler, implicit or explicit; the code in this run handler can be executed. They are persistent over repeated executions of a script. They can be saved to disk as files, and a compiled script file can be turned back into a script object. And script objects can even implement a relationship of inheritance with polymorphism. You can think of a script object as a powerful, semi-autonomous package for some code and variables that go together. This chapter presents script objects and their distinctive features.A script object is defined using a block with the keyword
script:script scriptName -- commands within the script object end script
A script object definition may appear anywhere. If defined at the top level of a script object (or script), it is a top-level entity ("Top-Level Entities," later in this chapter). It functions as a scope block . (The rules of scope appear in Chapter 10.) Read Chapter 6 for an overview of how script object definitions fit into a script's overall structure.A script object definition is just that—a definition. Merely encountering a script object definition in the course of execution does not cause of any of its commands to be executed. Rather, a script object definition is a form of variable initialization. So, for example:script s display dialog "howdy" end scriptThat code does not cause a dialog to display. It defines a script object with an implicit run handler; that run handler contains code that puts up a dialog, but the mere definition does not cause the run handler to run. The script object itself is the value of a variable. Here, that variable isEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Script Object Definition
- InhaltsvorschauA script object is defined using a block with the keyword
script:script scriptName -- commands within the script object end script
A script object definition may appear anywhere. If defined at the top level of a script object (or script), it is a top-level entity ("Top-Level Entities," later in this chapter). It functions as a scope block . (The rules of scope appear in Chapter 10.) Read Chapter 6 for an overview of how script object definitions fit into a script's overall structure.A script object definition is just that—a definition. Merely encountering a script object definition in the course of execution does not cause of any of its commands to be executed. Rather, a script object definition is a form of variable initialization. So, for example:script s display dialog "howdy" end scriptThat code does not cause a dialog to display. It defines a script object with an implicit run handler; that run handler contains code that puts up a dialog, but the mere definition does not cause the run handler to run. The script object itself is the value of a variable. Here, that variable iss; when this code is encountered, the variablesis defined and initialized, and its initial value is the script object described by this block of code.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Run Handler
- InhaltsvorschauEvery script object has exactly one run handler. This may be explicit (all the code marked off by an
on runblock) or implicit (all the code at the top level of the script object). See "Code and the Run Handler" in Chapter 6.To execute the code in a script object's run handler, you send therunmessage to it. You can do this by making the script object the direct object of theruncommand, or by sayingrunwithin a tell block targeting the script object. So, for example:script s display dialog "howdy" end script run s -- HowdyOr:script s display dialog "howdy" end script tell s run -- Howdy end tellA one-line tell block can be reduced to a single line of code with no block:script s display dialog "howdy" end script tell s to run -- Howdy(On the result of a run handler, see "Returned Value" in Chapter 9. On passing parameters to a run handler, see "The Run Handler" in Chapter 9.)If a script object has no explicit run handler and has no executable statements in its implicit run handler, telling it to run can have unpredictable consequences (this fact is almost certainly a bug). For example, this would be a bad thing to do:script myScript end script run myScript -- error: stack overflowEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Script Properties
- InhaltsvorschauA script property (often just called a property) is a variable defined and initialized at the top level of a script object through a special statement called a property declaration . The syntax is:
property propertyName : initialValue
For example:script s property x : 5 end scriptThe abbreviation forpropertyisprop.A property is a variable, so its value can be set and fetched in the normal way. For example:script s property x : 10 display dialog x -- 10 set x to 5 display dialog x -- 5 end scriptA property declaration can appear only at the top level of a script object. But the script as a whole is a script object. Therefore a property declaration can appear at the top level of the script, and the script object that owns it is the script as a whole. This is a legal script:property x : 5 display dialog x
A script property declaration is likeset, not likecopy. When a script property is initialized to a value where this makes a difference (a list, a record, a date, or a script object) it is set by reference (see "Set by Reference" in Chapter 7). Here's proof:property L : {1, 2, 3} script s property LL : L set end of LL to 4 end script run s L -- {1, 2, 3, 4}Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Script Objects as Values
- InhaltsvorschauA script object is a datatype in AppleScript. This means that a variable's value can be a script object. In fact, a script object definition defines exactly such a variable. You can refer to this variable, and get and set its value, just as you would any other variable. Here, we fetch a script object as a value and assign it to another variable:
script myScript display dialog "Howdy" end script set x to myScript run x -- HowdyYou can also assign a new value to a variable whose value is a script object. No law says that this new value must be another script object; you're just replacing the value of the variable, as with any other variable. The original script object is lost if this variable name is your only way of referring to it. So, you could do this if you wanted:script myScript display dialog "Howdy" end script set myScript to 9 display dialog myScript -- 9You can assign to a variable whose value is a script object the value of another script object, in effect replacing its functionality with new functionality. Of course, that new functionality must be defined somewhere to begin with. The old functionality is lost if this variable name is your only way of referring to it. For example:script sayHowdy display dialog "Howdy" end script script sayGetLost display dialog "Get Lost" end script set sayHowdy to sayGetLost run sayHowdy -- Get LostWhen you useset(as opposed tocopy) to set a variable to a value that is a script object, you set the variable by reference (see "Set by Reference" in Chapter 7). So the script object is not copied; the variable's name becomes a new name for the script object, in addition to any existing names for the script object. This fact has two important implications:-
Setting a variable to a script object with
setis extremely efficient, no matter how big the script object may be. -
If a script object has more than one name, then whatever mutation is performed upon it by way of one name applies to it under its other names as well.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Top-Level Entities
- InhaltsvorschauA script object's top-level entities are variables defined at the top level of the script object having the special feature that even though they belong to the script object, and even though the rules of scope protect them from being visible to code outside the script object, they can be accessed (retrieved and assigned to) by code outside the script object. A top-level entity is either a script property, a handler, or a script object.The most important fact about a script object's top-level entities is that even though they are not directly visible to code outside the script object, they are accessible on demand to any code that can see the script object. This means that they can be both retrieved and assigned to (fetched and set) by such code.A special way of talking is required for doing this. Because a script object's top-level entities are not visible outside the script object, it is necessary, in effect, to ask the script object politely to yield access to a top-level entity (and the script object always politely complies). We say that to access a script object's top-level entities, you must target that script object. The syntax for doing this comes in two forms:
-
Use the
ofoperator (or the'soperator) to specify the top-level entity in relation to its script object. For example:script myScript property x : "Howdy" on sayHowdy( ) display dialog x end sayHowdy script innerScript display dialog x end script end script set x of myScript to "Hello" myScript's sayHowdy( ) -- Hello run innerScript of myScript -- Hello -
Alternatively, refer to the top-level entity within a tell block addressed to the script object. This requires the use of the keyword
its, except in the case of a handler call. For example:script myScript property x : "Howdy" on sayHowdy( ) display dialog x end sayHowdy script innerScript display dialog x end script end script tell myScript set its x to "Hello" sayHowdy( ) --
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Compiled Script Files as Script Objects
- InhaltsvorschauA script can read a compiled script file and incorporate its contents as a script object. Similarly, a script can save a script object out to disk as a compiled script file. You might use this mechanism as a means of implementing file-level persistence, or to build a separate library of commonly needed code that all scripts can share.The mechanism depends upon three verbs. They're not part of AppleScript proper, but are implemented in a scripting addition (Chapter 3) that's standard on all machines.load scriptSyntax
load script aliasOrFileDescriptionReturns the top-level script of the compiled script file or applet aliasOrFile as a script object.Exampleset myScript to load script alias "myDisk:myFile.scpt"
run scriptSyntaxrun script aliasOrFile [with parameters list]
DescriptionTells the top-level script of the compiled script file, applet, or text file aliasOrFile to run (compiling first if necessary), optionally handing it the list as the parameters for its explicit run handler, and returns the result.Examplerun script alias "myDisk:myFile.scpt"
store scriptSyntaxstore script scriptObject [in aliasOrFile [replacing yes|no]]
DescriptionSaves scriptObject to disk as a compiled script file or applet. Returns no value. If no further parameters are supplied, presents a Save File dialog; if the user cancels, a runtime error is raised. IfEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Inheritance
- InhaltsvorschauScript objects may be linked into a chain of inheritance . One script object inherits from another if the second script is the parent of the first. Then, suppose an attempt is made to access a top-level entity of the first script object (using the special syntax described in "Accessing Top-Level Entities," earlier in this chapter). If the script object has no such top-level entity, the attempt is passed along to its parent to see whether it has such a top-level entity.It turns out that every script object has a
parentproperty. This property is set for you if you don't set it (and so there is always an inheritance chain, even though you might not be aware of this). To link two script objects explicitly into a chain of inheritance, initialize theparentproperty of one to point to the other.Theparentproperty may be set only through initialization (that is, through a script property declaration). You cannot usecopyorsetto set it.In this example, we explicitly arrange two script objects,mommyandbaby, into an inheritance chain (by initializingbaby'sparentproperty). We can then tellbabyto execute a handler that it doesn't have, but whichmommydoes have. Here we go:script mommy on talk( ) display dialog "How do you do?" end talk end script script baby property parent : mommy end script baby's talk( ) -- How do you do?In that example, we told the child from outside to execute a handler that it doesn't have but the parent does. The child can also tell itself to execute such a handler:script mommy on talk( ) display dialog "How do you do?" end talk end script script baby property parent : mommy talk( ) end script run baby -- How do you do?Getting and setting properties works the same way. In this example, we get and set the value of a property ofbabythatbabydoesn't have:script mommy property address : "123 Main Street" end script script baby property parent : mommy end script display dialog baby's address --Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 9: Handlers
- InhaltsvorschauA handler is a subroutine within a script. A handler is an important form of flow control, and leads to better-behaved, better-organized, more reusable, and more legible code. With a handler, the same code can be executed from different places in a script. Even if a handler is going to be called only once in the course of a script, it's a useful organizational device because it names a block of code, and this name can describe the block's purpose.A handler is defined using a block with the keyword
on:on handlerName( ) -- commands within the handler end handlerName
A synonym foronisto.What follows the name of the handler in the on line of the block might be parentheses, but it might not. The real story is complicated; the details appear later in this chapter ("Syntax of Defining and Calling a Handler").A handler definition may appear only at the top level of a script object (or a script as a whole). It is a top-level entity of the script object ("Top-Level Entities" in Chapter 8). It functions as a scope block . (The rules of scope appear in Chapter 10.) Read Chapter 6 for an overview of how script object definitions fit into a script's overall structure.A handler definition is just that—a definition. Merely encountering a handler definition in the course of execution does not cause the handler to be executed. Rather, a handler definition is a form of variable definition. So, for example:on sayHowdy( ) display dialog "howdy" end sayHowdyThat code does not cause a dialog to display. It defines a handler whose code, if executed, would display a dialog. The handler itself is the value of a variable. Here, that variable issayHowdy; when this code is encountered, the variablesayHowdyis defined and initialized, and its initial value is the handler described by this block of code.What causes a handler's code to run is code that calls the handler. This looks essentially like using the handler's name, with some special syntax that signifies you're actually calling and not merely mentioning the name of the variable that contains the handler. So, for example:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Handler Definition
- InhaltsvorschauA handler is defined using a block with the keyword
on:on handlerName( ) -- commands within the handler end handlerName
A synonym foronisto.What follows the name of the handler in the on line of the block might be parentheses, but it might not. The real story is complicated; the details appear later in this chapter ("Syntax of Defining and Calling a Handler").A handler definition may appear only at the top level of a script object (or a script as a whole). It is a top-level entity of the script object ("Top-Level Entities" in Chapter 8). It functions as a scope block . (The rules of scope appear in Chapter 10.) Read Chapter 6 for an overview of how script object definitions fit into a script's overall structure.A handler definition is just that—a definition. Merely encountering a handler definition in the course of execution does not cause the handler to be executed. Rather, a handler definition is a form of variable definition. So, for example:on sayHowdy( ) display dialog "howdy" end sayHowdyThat code does not cause a dialog to display. It defines a handler whose code, if executed, would display a dialog. The handler itself is the value of a variable. Here, that variable issayHowdy; when this code is encountered, the variablesayHowdyis defined and initialized, and its initial value is the handler described by this block of code.What causes a handler's code to run is code that calls the handler. This looks essentially like using the handler's name, with some special syntax that signifies you're actually calling and not merely mentioning the name of the variable that contains the handler. So, for example:on sayHowdy( ) display dialog "howdy" end sayHowdy sayHowdy( )That code first defines a handler, then calls it. The call is in the last line. Because of that last line, the code does cause a dialog to be displayed.It is not an error to refer to a handler by its name alone, with no parentheses or parameters. This can be a useful thing to do, if you wish to refer to the handler as a value (see "Handlers as Values," later in this chapter); but itEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Returned Value
- InhaltsvorschauWhen a handler is executed, it may return a value. This value is the handler's result .The term result is used here in a technical sense. A handler may do other things besides return a result, and these other things may be quite significant in the world outside of the handler; but although these things may result from calling the handler, in a nontechnical sense, technically they are the handler's side effects, not its result. Thus, if you call a handler that erases your hard drive and returns the number
1, you might say, "The result of calling the handler was that my hard drive was erased," but technically you'd be wrong: the result was1; the erasure of your hard drive was a side effect . (Clearly a side effect can be much more important than a result.)When a handler is called, the result of executing the handler is essentially substituted as the value of the call that executed the handler.For example:on getRam( ) set bytes to system attribute "ram " return bytes div (2 ^ 20) end getRamThe handlergetRamreturns the amount of RAM installed on the user's machine, in megabytes. On my machine, it returns the number1024. This means that a call togetRam( )can presently be used wherever I would use the number1024; in effect, it is the number1024. For example:on getRam( ) set bytes to system attribute "ram " return bytes div (2 ^ 20) end getRam display dialog "You have " & getRam( ) & "MB of RAM. Wow!"The call togetRam( )in the last line behaves exactly as the number1024would behave in this context: it is a number, it is implicitly coerced to a string and concatenated with the other two strings (as explained under "Concatenation Operator" in Chapter 15), and the full resulting string is displayed to the user.The value returned by a handler is determined in one of two ways:- An explicit return
-
The handler, in the course of execution, encounters a line consisting of the keyword
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Handlers as Values
- InhaltsvorschauA handler is a datatype in AppleScript. This means that a variable's value can be a handler. In fact, a handler definition defines exactly such a variable. You can refer to this variable, and get and set its value, just as you would any other variable. Here, we fetch a handler as a value and assign it to another variable:
on sayHowdy( ) display dialog "Howdy" end sayHowdy set sayHello to sayHowdy sayHello( ) -- HowdyAs the example shows, after the assignment of the handler to another variable, we can call that variable as if it were a handler. That's because the variable is a handler.You can also assign a new value to a variable whose value is a handler. No law says that this new value must be another handler; you're just replacing the value of the variable, as with any other variable. The original handler functionality is lost. For example, you could do this if you wanted:on sayHowdy( ) display dialog "Howdy" end sayHowdy set sayHowdy to 9 display dialog sayHowdy -- 9You can assign to a variable whose value is a handler the value of another handler, in effect replacing its functionality with new functionality. Of course, that functionality has to be defined somewhere to begin with, and the old functionality is lost. For example:on sayHowdy( ) display dialog "Howdy" end sayHowdy on sayGetLost( ) display dialog "Get Lost" end sayGetLost set sayHello to sayGetLost sayHello( ) -- Get LostAn elegant use of this feature is a list that acts as a dispatch table . The idea is that sometimes we want to call one handler and sometimes another, depending on the circumstances. Rather than code the handler calls within a branching construct, we make a list of handlers and call the desired item of the list:on sayHello( ) display dialog "Hello" end sayHello on sayGetLost( ) display dialog "Get Lost" end sayGetLost set L to {sayHello, sayGetLost} -- for this example, we decide randomly which one to call set h to item (random number from 1 to 2) of L h( )Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Parameters
- InhaltsvorschauOne of the key features of a handler is that it can accept parameters . A parameter is a value passed to the handler as it is called. The handler can see these values, and can react to them. Thus, the handler can do different things depending on the values actually passed as parameters on each occasion when the handler is called.For example, here's a definition of a handler that takes two parameters, and a call to that handler:
on subtract(x, y) return x - y end subtract subtract(3, 2) -- 1In the last line, the handler is called with the two parameters it requires. The value3is passed as the first parameter; the value2is passed as the second parameter. In the handler definition, names that effectively designate variables belonging to the handler have been declared. When the handler is called, and before it actually starts executing, these names are paired with the parameters that were passed, and the corresponding values are assigned. Thus, whenadd( )is called on this occasion, it is as if it had a variablexwhich has been initialized to3, and a variableywhich has been initialized to2. Thus, the result is1. But the result would have been different if the parameter values passed in the last line had been10and8. That's the point of parameters.The names of the parameters within the handler, such asxandyin this example, designate variables local to the handler. The meaning and significance of this is explained in Chapter 10, but the key fact is that the names of the parameters in the handler definition have nothing to do with the names of the values passed as parameters. Consider this example:on subtract(x, y) return x - y end subtract set x to 2 set y to 3 subtract(y, x) -- 1The handler subtractsyfromx. If these were the same as theyandxat the top level of the script, you'd expect the result to be negative (we'd be subtracting 3 from 2). But in the handler call, the names are not what matters—the values are. The valueEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Pass by Reference
- InhaltsvorschauParameters passed to a handler, and the value returned from a handler, are normally passed by value in AppleScript. This means that a copy of the value is passed to, and used by, the handler code.But four datatypes—lists, records, dates, and script objects—when they are passed as parameters to a handler, are passed by reference , meaning that no copy is made; the handler and the caller both end up with access to the very same value. These are the only mutable datatypes—the only datatypes whose values can be modified in place. Whatever mutation is made to the parameter by the handler applies to it in the context of the caller as well. (Compare "Set by Reference" in Chapter 7.)Here's an example showing that a list is passed by reference:
on extend(LL) set end of LL to "Jack" end extend set L to {"Mannie", "Moe"} extend(L) L -- {"Mannie", "Moe", "Jack"}Even though the caller didn't capture the value of the handler callextend( ), and even though the caller didn't changeL, and even though the handlerextendnever speaks explicitly ofL, yet after the call,Lhas changed in the caller's context. The handlerextendwas able to modifyL.Here's an example showing that a script object is passed by reference:script myScript property x : 10 end script on myHandler(s) set s's x to 20 end myHandler myHandler(myScript) display dialog myScript's x -- 20It makes sense that these datatypes can be passed by reference, but it is a little disturbing that they are passed by reference automatically, without giving you any choice in the matter. Passing by reference gives the handler great power over the parameter, which the handler can misuse. So, to prevent accidents, it is up to you to remember that list, record, date, and script object parameters are passed by reference, and that things you do in a handler to such parameters have an effect outside the handler. If you wish to avoid this, then if you like you can pass them by value, by making a copy and passing the copy:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Syntax of Defining and Calling a Handler
- InhaltsvorschauThe way a handler is defined (in the
online) states how many parameters the handler takes (and also supplies names for variables in the handler to which the parameter values will be assigned during a call). A call to the handler must correspond, supplying parameters correctly. It is a runtime error to call a handler with fewer parameters than the definition of the handler requires:on greet(what) display dialog what end greet greet( ) -- error: {} doesn't match the parameters {what} for greetThe nitty-gritty of how a handler's definition states how many parameters there are, and how a corresponding call to that handler must be phrased, is remarkably complicated. There are actually four cases that must be distinguished (though you are most likely to use only the first two in handlers that you define). I'll discuss these four cases in a moment, but first I want to talk about the problem of optional parameters.Officially, there is no way to declare a parameter optional in AppleScript. On the other hand, you really don't need a way to do this, because a parameter can be a list or a record, which can have any number of items. (Gosh, all we need is ashiftcommand and this would be Perl!)For example, here's a handler that calculates the area of a rectangle given the lengths of the two sides. If you pass the length of only one side, the rectangle is assumed to be a square:on area(L) set a to item 1 of L if (count L) = 2 then set b to item 2 of L else set b to item 1 of L end if return a * b end area area({3, 4}) -- 12 area({3}) -- 9A record used as a parameter is often an even better way to simulate optional parameters because it allows you to simulate default values for missing parameters as well. A single concatenation lets you merge the defaults into the parameter record without upsetting the values that are already there (see "Record" in Chapter 13; use of this device in this context was suggested to me by Scott Babcock). For example:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Event Handlers
- InhaltsvorschauHandlers that you define freely in code are user handlers. But there are also handlers whose definition comes from the dictionary of some scripting addition or application. These are event handlers (a command defined in a dictionary is technically called an event, because it is actually an Apple event, as discussed in Chapter 3).An event handler 's parameter syntax is a little different from that of a user handler :
- No parameters
-
The handler takes no parentheses.
- First parameter
-
The first parameter (the direct object) simply follows the handler name directly, without parentheses.
- Subsequent parameters
-
Subsequent parameters are labeled. Labeled parameters are the same as prepositional parameters, but the labels are not limited to the list in Table 9-1; basically, the dictionary can define any labels it likes.
Also, the name of the command, and any of the labels, can consist of multiple words .An event handler is often used in connection with an automatic location (Chapter 2). Some application is going to send a message to your script, and it has defined what that message will be. To receive the message, your script must contain an event handler with a matching definition. The event handler is an entry point to your script.Take, for example, folder actions (Chapter 26). You can attach a script to a folder as a folder action, so your script is called (by the System Events application) when certain things happen in the Finder. Let's say you want your script to be called when files are put into that folder. Then your script must contain an event handler with this structure:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The Run Handler
- InhaltsvorschauThe run handler of a script object (or script) has been discussed in "Code and the Run Handler" in Chapter 6 and "Run Handler" in Chapter 8. The run handler is an event handler. Thus it has event handler syntax; it takes no parentheses, either in the definition or in the call.It turns out that an explicit run handler may take parameters . This ability is useful only under special circumstances, and in fact it prevents the script object (or script) from running at all under normal circumstances, because you usually have no way to supply these parameters in the call.The official syntax for defining a run handler with parameters is to express all parameters as a single list. For example:
script s on run {what, what2} display dialog what & space & what2 end run end scriptYou can't simply tell that script object to run, because you can't supply the parameters. If you try, you'll get an error at runtime:run s -- error: «script s» doesn't match the parameters {what, what2} for runOne solution is to use therun scriptcommand, which permits parameters to be passed to a run handler:run script s with parameters {"howdy", "there"}That approach is rather extreme;run scriptis expensive , because it requires the creation (and destruction) of an entire separate instance of the AppleScript scripting component. A clever and inexpensive approach (which I owe to Michael Terry) is to take advantage of script object inheritance (Chapter 8) and thecontinuecommand, which can pass parameters to any event:property args : null script s on run {what, what2} display dialog what & space & what2 end run end script script trampoline property parent : s continue run args end script set args to {"howdy", "there"} run trampolineIf you give your script as a whole an explicit run handler that expects parameters, you won't be able to run your script in the Script Editor or in most script runners. For example:on run {what} display dialog what end runEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Recursion
- InhaltsvorschauA handler is visible from within itself. This means that recursion is possible; a handler may call itself.Explaining the elegances and dangers of recursion is beyond the scope of this book. The best way to learn about recursion is through a language like Scheme or LISP , where recursion is the primary form of looping. In fact, in conjunction with lists, AppleScript's recursion allows some remarkably Scheme-like (or LISP-like) modes of expression (see "LISP-likeness " in Chapter 4).The best way to learn Scheme is to read Harold Abelson et al., Structure and Interpretation of Computer Programs, 2nd Edition (MIT Press, 1996), the best computer book ever written.For example, here's a recursive routine for filtering a list. We'll remove from the list everything that isn't a number:
on filter(L) if L = {} then return L if {class of item 1 of L} is in {real, integer, number} then return {item 1 of L} & filter(rest of L) else return filter(rest of L) end if end filter filter({"hey", 1, "ho", 2, 3}) -- {1, 2, 3}AppleScript is not a truly recursive language, however; recursion is limited by the depth of AppleScript's internal stack. If you recurse too deep (which usually means recursing through too long a list), you'll get a "stack overflow " error message. Unfortunately there's no way to know in advance what the limit is, as it depends on what happens during each recursion and on what environment is running the script. Just to give a typical example, using Script Editor on my machine, this code runs fine ifmaxis 504 but fails with a stack overflow ifmaxis 505; but in Smile it works even ifmaxis as large as 8159:on remvix(L, ix) if L is {} then return {} if ix is 1 then return rest of L else return item 1 of L & remvix(rest of L, ix - 1) end if end remvix set L to {} set max to 505 repeat with x from 1 to max set end of L to x end repeat remvix(L, max)Be careful when assigning a recursive handler as a value to a variable. At the point where the handler calls itself, its name is hard-coded into its functionality. After assigning the handler functionality to a different variable name, that name may no longer be in scope and the handler will break when called under its new name:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Power Handler Tricks
- InhaltsvorschauA handler takes values as parameters and returns a value. A handler is a value. A script object is a value and can contain a handler. If these facts suggest to your mind an intimation of amazing possibilities, read on.You can pass a handler as a parameter to handler. The difficulty is in calling it. This code fails with a runtime error:
on sayHowdy( ) display dialog "Howdy" end sayHowdy on doThis(what) what( ) end doThis doThis(sayHowdy) -- error: «script» doesn't understand the what messageThe trouble is that AppleScript refuses to identify thewhat( )in the handler call with thewhatthat arrived as a parameter. This is actually another case of the rule (see "Handler Calls, Commands, and Script Objects" in Chapter 8) that an unqualified handler call is a message directed to the current script object, which in this case is the script as a whole.One possible workaround is to use a global. This approach works because by copying the handler to a global we're putting it where a message directed to the script as a whole can find it (see "Scope of Globals" in Chapter 10):on sayHowdy( ) display dialog "Howdy" end sayHowdy on doThis(what) global what2 set what2 to what what2( ) end doThis doThis(sayHowdy) -- HowdyThis solution is clever, but now we've broken encapsulation. Global variables pose risks (other code might access this same global, or we might be tromping accidentally on some other code's global), and besides, if we're going to use a global there's little point to passing a parameter in the first place.Another possible workaround is to pass a script object instead of a handler:script sayHowdy display dialog "Howdy" end script on doThis(what) run what end doThis doThis(sayHowdy) -- HowdyThis is very efficient because script objects are passed by reference. But we ended up having to use theruncommand instead of a handler call. That's not going to be very pretty if our handler takes any parameters, because it's hard to pass parameters to a run handler (as shown earlier in this chapter). But wait—a script object can contain a handler! So we can use it as a kind of envelope. We can define a handler in a script object and pass the script object. In fact, this device permits both the script and the handler that receives it as a parameter to be completely general:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 10: Scope
- InhaltsvorschauBy scope is meant the ability of one region of code to see variables in another region of code. The rules of scope for AppleScript are remarkably involved—as involved of those of any computer language I know. They are a perennial source of pitfalls for beginning and experienced programmers alike. If you don't understand the rules of scope, or (even worse) if you try to ignore them, you'll find your scripts mysteriously going wrong in confusing ways. This chapter discusses the rules of scope, along with a powerful advanced scope-related feature of AppleScript—closures.Every AppleScript program has regions of scope . Some regions of scope may be inside others, but they do not partially intersect—given two regions, either one is entirely inside the other or they are completely distinct. In other words, the regions of scope are nested. The top level of the script is a script object and is a region of scope . Any other regions of scope are inside this, and are created by the presence of scope blocks: handler definitions and script object definitions. (See Chapter 6.)In Example 10-1, I've sketched a sample script with scope blocks nested in various combinations. At every point where code can go, I've put a comment distinguishing that region of scope by number. So, scope 1 is the top level of the script itself (its implicit run handler); scope 2 is the code within
handlerOne, a handler defined at the top level of the script; scope 3 is the code withinscriptOne, a script object defined withinhandlerOne; and so on.Example 10-1. Regions of scope (continued)-- scope 1 on handlerOne( ) -- scope 2 script scriptOne -- scope 3 end script -- scope 2 end handlerOne -- scope 1 script scriptTwo -- scope 5 on handlerTwo( ) -- scope 6 end handlerTwo -- scope 5 script scriptThree -- scope 7 end script -- scope 5 end script -- scope 1
The region in which a variable is visible is called itsEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Regions of Scope
- InhaltsvorschauEvery AppleScript program has regions of scope . Some regions of scope may be inside others, but they do not partially intersect—given two regions, either one is entirely inside the other or they are completely distinct. In other words, the regions of scope are nested. The top level of the script is a script object and is a region of scope . Any other regions of scope are inside this, and are created by the presence of scope blocks: handler definitions and script object definitions. (See Chapter 6.)In Example 10-1, I've sketched a sample script with scope blocks nested in various combinations. At every point where code can go, I've put a comment distinguishing that region of scope by number. So, scope 1 is the top level of the script itself (its implicit run handler); scope 2 is the code within
handlerOne, a handler defined at the top level of the script; scope 3 is the code withinscriptOne, a script object defined withinhandlerOne; and so on.Example 10-1. Regions of scope (continued)-- scope 1 on handlerOne( ) -- scope 2 script scriptOne -- scope 3 end script -- scope 2 end handlerOne -- scope 1 script scriptTwo -- scope 5 on handlerTwo( ) -- scope 6 end handlerTwo -- scope 5 script scriptThree -- scope 7 end script -- scope 5 end script -- scope 1
The region in which a variable is visible is called its scope. A variable that is visible at a certain point is said to be in scope at that point. To understand scope is to know what kinds of variable can belong to a given region of scope and in what other regions each variable is in scope.Note that visibility is visibility and access is access. If code can see a variable in any manner, it can access it, which means it can both get and set that variable. In the examples in this chapter I will mostly use getting rather than setting, because that's the simplest way to detect when code can't see a variable (the attempt to fetch the value of an undefined variable results in a runtime error—see Chapter 7).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Kinds of Variable
- InhaltsvorschauWith regard to scope, we must distinguish four kinds of variable:
- Top-level entities
-
Top-level entities are script properties declared, and script objects and handlers defined, at the top level of a script or script object. (See "Top-Level Entities" in Chapter 8.)
- Explicit locals
-
An explicit local is a variable announced by a local declaration , which looks like this:
local x
- Explicit globals
-
An explicit global is a variable announced by a global declaration, which looks like this:
global x
- Undeclared variables
-
A undeclared variable is none of the above. It's just a name that your code suddenly starts using. This is legal, but when you do it, AppleScript assigns the variable a scope , in ways that may surprise you.
The scope of a variable, and what kind of variable it is (these amount to the same thing), are determined at compile time .Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Scope of Top-Level Entities
- InhaltsvorschauA top-level entity is visible in the scope where it is defined, and at all deeper levels nested in that scope subsequent to where it is defined.Let's take, for example, a script property. The script property
xhere, declared at the top level of the script as a whole, is also in scope inside a script object and a handler:property x : 10 script myScript display dialog x end script on myHandler( ) display dialog x end myHandler run myScript -- 10 myHandler( ) -- 10If a top-level entity is in scope in a script object, a script object nested at a deeper level may declare a top-level entity with the same name. This deeper name will overshadow the first entity's name within that deeper scope. Thus in this example there is never the slightest ambiguity as to what is meant byxat any point:property x : 5 script scriptOne property x : 10 script scriptTwo property x : 20 display dialog x end script display dialog x run scriptTwo end script script scriptThree property x : 30 display dialog x end script script scriptFour display dialog x end script display dialog x -- 5 run scriptOne -- 10, 20 run scriptThree -- 30 run scriptFour -- 5Regions of scope outside a script object cannot see that script object's top-level entities. But if they can see a name referring to that script object, they can ask to access that script's top-level entities, as explained in "Top-Level Entities" in Chapter 8. In the same way, a region of scope at a deeper level can access an overshadowed name:script scriptOne property x : 10 script inner property x : 20 display dialog scriptOne's x -- 10 end script end script script scriptTwo display dialog scriptOne's x -- 10 display dialog x -- error: The variable x is not defined end script run scriptOne's inner run scriptTwoIn that example,scriptOneis a top-level entity of the top-level script (that's where it's defined). For that reason (and because the namescriptOneis not overshadowed), scriptEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Scope of Locals
- InhaltsvorschauAn explicit local is a variable whose name appears in a local declaration . A local declaration can declare several variables at once, delimited by comma:
local a local b, c, d
A local variable is visible only within the very same region of scope where it is declared—not outside it, and not at a deeper level. (But there's an exception, which we'll come to in a moment.)Local variables completely disambiguate a name within their own scope, and local variables in other scopes can have the same name without conflict. Suppose a script object starts like this:script myScript local xThe local declaration forxmeans that from now on when code in this script object's scope saysxit means this localxand no other. What's more, other scopes may declare their own localx, they may declare a globalx, they may bang the floor and have a temper tantrum, but they absolutely will not be able to have any effect uponmyScript'sx, nor will anythingmyScriptdoes with itsxhave any effect upon them.Here's an example of a local variable in action:local x set x to 5 script myScript display dialog x -- error: The variable x is not defined end script run myScriptObserve how completely different this is from what would have happened ifxhad been a top-level property. Here, there is a variable calledxand it is defined, but it is declared local and therefore is visible only within its own scope. That scope is the top-level script. Thedisplay dialog xcommand is in a different scope, that of the script objectmyScript. Therefore AppleScript takes this to be a differentx, and this differentxhas never been assigned a value. (I'll explain later just whatxAppleScript takes thexofdisplay dialog xto be.)A local declaration overshadows the visibility of a top-level entity from a higher level:property x : 5 script myScript local x display dialog x -- error: The variable x is not defined end script run myScriptEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Scope of Globals
- InhaltsvorschauAn explicit global is a variable whose name appears in a global declaration . A global declaration can declare several variables at once, delimited by comma:
global a global b, c, d
Globals are rather complicated. I'll divide the discussion into two parts: the downward effect of a global declaration, and its upward effect.The downward effect of a global declaration is very much like a top-level entity declaration. A variable declared global is visible in the scope where it is defined, subsequent to the point where it is defined, and at all deeper levels within that scope, subsequent to the point where it is defined.For example:global x set x to 5 on myHandler( ) display dialog x end myHandler myHandler( ) -- 5The variablexis declared global; it is then visible downward into the scope ofmyHandler, becausemyHandleris defined subsequently in the same scope asx.But the following code does not work:set x to 5 on myHandler( ) display dialog x end myHandler global x set x to 10 myHandler( ) -- error: The variable x is not definedWe keep settingxlike mad, but to no avail; the global declaration doesn't come until after the handler definition, so code inside the handler can't seex.Just as with a top-level entity, a global's downward effect is overshadowed by a local declaration of the same variable name at a deeper level, and this overshadowing affects only the scope of the local declaration—not a deeper scope.The upward effect of a global declaration of a variable is to identify that variable with a variable at the top level of the script with the same name (creating this variable if it does not already exist). This means that separate regions of scope can share a variable simply by declaring it global:on setX( ) global x set x to 5 end setX on getX( ) global x display dialog x end getX setX( ) getX( ) --Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Scope of Undeclared Variables
- InhaltsvorschauIn AppleScript, you do not have to declare variables. When you use a name that, by the preceding rules of scope, is not an existing variable, AppleScript does not complain; rather, it creates the variable for you. How it does this depends upon the location of the code that uses the nonexistent variable name:
- Code at the top level
-
The variable is created as a global. There is no explicit global declaration, so there is no downward effect, but other scopes can see this variable through a global declaration. I call this an implicit global.
- Code not at the top level
-
The variable is created as a local. I call this an implicit local .
Let's illustrate an implicit global first:set x to 5 on getX( ) global x display dialog x end getX getX( ) -- 5The first line never said explicitly thatxshould be a global. But it clearly is one, since whengetXcomes along and asks to see a global calledx, thexcreated in the first line is what it sees. (Incidentally, you can move the "set x to 5" line to after thegetXhandler definition and the script will still work; the important thing is that the globalxbe defined by the timegetXruns, not necessarily beforegetXitself is defined.)Incidentally, a variable created implicitly in a script's top-level explicit run handler is an implicit global as well, just as if you'd declared it at the absolute top level:on run set howdy to "Howdy" sayHowdy( ) -- Howdy end run on sayHowdy( ) global howdy display dialog howdy end sayHowdyThat's a very odd rule, as in no other respect (I believe) is an explicit run handler treated like the absolute top level; usually, it's treated like a handler, in which case the implicit variable would be local. This shows the extremes the language goes to in order to cope with undeclared variables.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Declare Your Variables
- InhaltsvorschauSounds like "eat your vegetables," doesn't it? Well, it should. Each motto is good advice, no matter how unpalatable it may seem at first. I strongly advise you to declare all your variables—even (especially!) your locals. Unfortunately, AppleScript gives you no help with this; you can't make it warn you when a variable is undeclared. Rather, it silently declares it for you. This behavior, doubtless intended to make programming in AppleScript easier, is in fact the source of more mistakes and confusion among AppleScript programmers than any other feature of the language.The trouble is that if you are lulled into a false sense of security because there's no need to declare your variables, then you can be surprised when some other scope tramples them. For example, imagine that your script starts like this:
set x to 5
That's top-level code, so you've just implicitly declaredxa global. This means that any other handler or script object anywhere in this script can access yourxand change its value, just by saying this:global x
This other code may not have intended to trample on yourx; perhaps it was trying to establish a global of its own, possibly in order to communicate its value to code at a lower level, or to function as persistent storage between calls. But the damage is done, just because of the upward effects of a global declaration. And to think that you could have prevented this by declaring your top-levelxlocal to start with.The converse is also true. Pretend that you have a large script and that this code occurs somewhere within it:on myHandler( ) set x to 5 endIsxa local or a global here? You don't know! It depends upon the context. Ifxhas previously been declared global at a higher level, thisxis global (by the downward effect of that declaration). If not, thisxis local. But it is intolerable that you should have to search elsewhere to learn the scope ofxwithinmyHandler!A particularly tricky problem is presented by script objects loaded from a compiled script file on disk (see Chapter 8). For example:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Free Variables
- InhaltsvorschauA variable defined outside a handler or script object, but globally visible within it, and not overshadowed by a declaration of the same name, is called a free variable with respect to that handler or script object. A free variable in AppleScript is identified with a top-level entity or global through the downward effect of its declaration. For example:
global x, y, z script myScript property x : 1 local y yy z end scriptWithinmyScript,xis explicitly defined as a property andyis explicitly defined as a local, so neither is a free variable. The variableyyisn't explicitly defined withinmyScript, but it isn't defined outside it either, so it is an implicit local and not a free variable. But the variablezis globally visible withinmyScript(from the global declaration at the start of the code), and the name is not redeclared withinmyScript, sozwithinmyScriptis a free variable, and is identified with the globalzdeclared in the first line.A free variable takes its value within the handler or script object at the time the code runs, not at the time the handler or script object is defined. For example:global x set x to 5 on myHandler( ) display dialog x -- x is a free variable end myHandler set x to 10 myHandler( ) -- 10 (not 5)The dialog displays10, not5. It doesn't matter thatxhad been set to 5 whenmyHandlerwas defined; it only matters what its value is when the code insidemyHandleractually runs. By that time,xhas been set to 10.Free variables' values are determined at runtime; but the identification of the fact that a variable is a free variable, and its association with some particular globally visible variable, happens during compilation. This way of resolving the meaning of free variable names is called lexical scoping .So, in the previous example, it is important thatxis declared global beforemyHandleris defined. If you move theglobal xdeclaration to after themyHandlerdefinition, the script generates an error at runtime. Even ifEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Redeclaration of Variables
- InhaltsvorschauRedeclaration of variables is a nasty edge case, testing the limits of the language. Luckily, the compiler mostly stops you from doing it. But there is a great deal of legal nuttiness, especially among declarations at the top level of a script. Essentially AppleScript is hoist with its own petard: having ruled that variables can be declared implicitly, and that global variables exist at top level even when they are declared elsewhere, AppleScript is simply trying to cope coherently with the consequences.Here are some examples of what happens when you redeclare a variable.It is a compile-time error to redeclare an implicit global as local:
set x to 5 local x -- compile-time error: Can't declare x as both a local and global variableIt is a compile-time error to redeclare an implicit local as global:on getX( ) display dialog x global x -- compile-time error: Can't declare x as both a local and global variable end getXBy the same token, it is a compile-time error to declare a handler parameter as global within the handler:on myHandler(what) global what -- compile-time error: Can't declare x as both a local and global variable endIt is a compile-time error to redeclare as local a variable declared global in the same scope (except at the top level):on getX( ) global x local x -- compile-time error: Can't declare x as both a local and global variable end getXIt is a compile-time error to redeclare as global a variable declared local in the same scope (except at the top level):on getX( ) local x global x -- compile-time error: Can't declare x as both a local and global variable end getXAt the top level, it is not an error to declare a variable local and then declare it global in the same scope. But it doesn't have any effect within the top-level scope either. For example:local x global x set x to 5 on setX( ) set x to 10 end setX on getX( ) display dialog x end getX setX( ) getX( ) -- 10 display dialog x --Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Closures
- InhaltsvorschauA closure is one of those delightfully LISPy things that turns up in AppleScript. The subject is rather advanced, though, so don't feel you have to understand everything in this section at once.It turns out that a script object may capture certain aspects of its context, maintaining this context even though the script object may run later in a different context. For example:
property x : 5 script myScript display dialog x end script set x to 20 set dummy to myScript set x to 10 run myScript -- 20That is extremely odd. It violates the rule stated earlier ("Free Variables") about the value of free variables being determined at runtime. By the timemyScriptruns, its free variablexhas been set to 10, yet the dialog displays 20. The proximate cause turns out to be the mysterious line "set dummy to myScript." If that line is removed, the dialog says 10, just as we expect. Yet it is hard to see what difference that one line can make. It's not as if we ever do anything with the variabledummy, after all. We simply assign to it and forget about it. So what's going on?The rule appears to be that the mere act of assigning a script object variable to another variable—it can equally be acopyas aset—causes the script object to become a closure . A closure is a scope block plus the values of its free variables at that moment.The example is structured in three parts so as to demonstrate the phenomenon fully. First, a property declaration precedes the script definition; this is howxinside the script definition becomes a free variable at compile time. Then, the script object is assigned to another variable; at that moment the closure is formed. The free variable has a different value by this time, so this is the value that gets frozen into the closure. Finally, the free variable's value is changed again and the script object is executed; but the script object was already turned into a closure, so the change in the value of top-levelxhas no effect on it.If, at the start of that example, we substitute a global declaration for the property declaration, the example doesn't work: we don't get a closure. Rather, the dialog displays 10, the value ofEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 11: Objects
- InhaltsvorschauThe purpose of AppleScript is to communicate with scriptable applications. Within the language, these applications present themselves as objects—things to which you send messages, asking for access to their private world of attributes. This metaphor has been extended in AppleScript in a general way (though not, perhaps, with perfect rigor or consistency) to pervade the whole language, so that every value within it is, to a greater or lesser degree, somewhat like a scriptable application. Thus, whether or not AppleScript is an object -oriented language, or even an object-based language, it has a general flavor of involving objects: at every moment in your code, you are talking to something, and most of the things to which you talk have attributes. This chapter is about aspects of the language that involve talking to objects and referring to their attributes.The fundamental activity in AppleScript is that of sending messages. Every line of code contains at least one imperative verb. There are actually two kinds of imperative verb: a handler call, which matches a handler definition in your script, and a command , which matches an event defined in a dictionary. The imperative verb is always directed to some specific target , which is supposed to obey it. The medium of communication between the imperative verb in your code and the target that you're talking to is a message .An object is anything that can be targeted by a message. The most important targets in AppleScript are scriptable applications, but a script object can be a target too, and indeed, in some sense, every value can be a target. So, to that extent, everything in AppleScript is a kind of object. (See also "Object-likeness" in Chapter 4.) For example,
countis a command. In a context where the target is the Finder, sayingcountcauses a message to be sent to the Finder. In a context where the target is a script object, sayingcountcauses a message to be sent to that script object. In a context where the target is a string, sayingEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Messages
- InhaltsvorschauThe fundamental activity in AppleScript is that of sending messages. Every line of code contains at least one imperative verb. There are actually two kinds of imperative verb: a handler call, which matches a handler definition in your script, and a command , which matches an event defined in a dictionary. The imperative verb is always directed to some specific target , which is supposed to obey it. The medium of communication between the imperative verb in your code and the target that you're talking to is a message .An object is anything that can be targeted by a message. The most important targets in AppleScript are scriptable applications, but a script object can be a target too, and indeed, in some sense, every value can be a target. So, to that extent, everything in AppleScript is a kind of object. (See also "Object-likeness" in Chapter 4.) For example,
countis a command. In a context where the target is the Finder, sayingcountcauses a message to be sent to the Finder. In a context where the target is a script object, sayingcountcauses a message to be sent to that script object. In a context where the target is a string, sayingcountcauses a message to be sent to that string.AppleScript tries to give the impression that all messages have the same status. Consider, for instance, what happens when an object can't obey a message. If the target is anything other than an application, we are told that the object "doesn't understand the so-and-so message." If the target is an application, we are told: "Can't continue so-and-so." The wording of the error is the same, though, no matter whether the imperative verb that generated the message is a handler call or a command.tell 1 count -- error: 1 doesn't understand the count message end tell script s end script tell s h( ) -- error: «script s» doesn't understand the h message end tell tell application "Finder" tell folder 1 using terms from application "iPhoto" start slideshow --Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Attributes
- InhaltsvorschauThe second way in which values are object-like in AppleScript is that they can have attributes . A attribute is a named value belonging to the object. The most intuitive way to understand attributes is through the notion "has." A list has a length; a string has characters; a folder has a name; an iTunes track has an artist.There are two important things to understand about attributes. First, attributes are values like any other values, which means they are themselves objects. There is thus a relationship between two objects as owner and attribute. The object that is the attribute may itself have attributes, and so we can end up with a vast chain or tree linking many objects. This structure is called an object model and is crucial to your understanding of how to talk to a scriptable application. Every scriptable application has an object model, which functions as your map of that application's world.Second, attributes are accessible only through their owner. For example, iTunes has a huge object model representing all the tracks in all your playlists, and all the various attributes of those tracks; but there is only one object to which you have direct access—the iTunes application. All the rest of iTunes's object model belongs to iTunes, and to access any object in it, you have to ask iTunes. If this reminds you of how script objects and their top-level entities work, it should (see "Top-Level Entities" in Chapter 8).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Class
- InhaltsvorschauEvery value is of some fixed and definite type . I usually refer to this as its datatype , but the AppleScript term for speaking of a value's type is class . You can use the term
classto inquire of any value what its datatype is:class of 7 -- integer class of "howdy" -- string class of {"Mannie"} -- list class of class of 1975 -- class
As the last line shows, even something'sclassis a value and therefore has to have a class, namelyclass.Strictly speaking, the datatype of terms likeintegerandclassis not reallyclassbut rathertype class. It's as if every value has an attribute calledclasswhose value is itself atype class. However, AppleScript will never tell you that the class of anything istype class. You may see a class referred to as type, though, in a dictionary or error message:2 as boolean -- error: Can't make 2 into type booleanYou can assign a value of any class to any variable, but at a given moment a variable has only one value and that value has only one class (so it is customary to speak of a variable's class, meaning the class of the value it has at that moment).It is the class of something that determines what messages can be sent to it and what attributes it has. For example, a list has a length because it is a list. I am guaranteed that I can ask any list for its length and get back a meaningful answer. I am also guaranteed that I can send thecountmessage to any list and get back a meaningful response (the same as its length, actually).The classes of many of the objects you'll be interested in when you're working with AppleScript will be classes defined by some particular scriptable application. This is unfortunate, because such classes are much harder to work with than, say, a list. A list is always a list, but two classes with the same name, defined by two different applications, might well be nothing like one another. The Finder has a folder class and Entourage has a folder class, but a Finder folder and an Entourage folder have virtually nothing in common; they have totally different sets of attributes. Indeed, both the Finder and Entourage themselves belong to the application class, but they have very little in common too. And when it comes to messages, things are even worse; the Finder knows very well what messages it is legal to send to one of its folders, but the Finder's dictionary does little or nothing to tell you what they are. There will be much more groaning about this in Chapter 20.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Target
- InhaltsvorschauAt every moment in AppleScript code, you are speaking to some object. That object is the target , to which all messages will be sent, unless you specify otherwise. Knowing what object is the target, and how to specify a desired target, is very important to your successful use of AppleScript.The implicit target is the current script or script object. (See "Handler Calls, Commands, and Script Objects" in Chapter 8.) In this code, the implicit target is the script itself:
count
In this code, the implicit target is the script objectmyScript:script myScript count end scriptThere are three ways to specify an explicit target: as a direct object of a command , with a tell block, and with theofoperator or one of its synonyms. These three ways may be combined to specify the complete target. (If they remind you of ways you can talk to a script object and access its top-level entities, they should; see Chapter 8.)Most commands take at least one parameter. The unnamed parameter that directly follows the name of the command is the direct object. In the absence of any other target information, the target can occupy the place of the direct object.In this example, we see thecountmessage being sent to various targets, each of which interprets it in a different way:script s on count return "1, 2, 3, ha ha ha" end count end script count s -- "1, 2, 3, ha ha ha" count "hello" -- 5 count {1, 2, 3} -- 3 count application "Finder" -- 32 (the number of desktop items)It is permitted to insert the wordofbetween the command and the direct object (unless the command isget,set, orcopy). It is also permitted to insert the wordgetbefore the command. This is rather confusing because it makes a command (such ascount) look like an attribute, and I do not recommend talking this way.count of "hello" -- 5 get count of "hello" -- 5 script s display dialog "howdy" end script get run of s -- howdy, but no one ever talks like this
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Get
- InhaltsvorschauThe default command is
get. In effect, a sentence or clause with no verb is assumed to havegetas its verb. So, for example:tell application "Finder" name of folder 1 end tellThegetcommand is supplied here and is the actual message sent to the Finder. It's exactly as if you had saidgetexplicitly:tell application "Finder" get name of folder 1 end tellOne even sees code written like this:tell application "Finder" to name of folder 1
AppleScript can also supplygetin the middle of a line where needed. As we have already seen, this code:tell application "Finder" set oldname to name of folder 1 end tellis actually treated by AppleScript as if it said this:tell application "Finder" set oldname to (get name of folder 1) end tellDo not imagine, however, that it makes no difference whether you ever sayget, and that you can blithely omit it. On the contrary, it's probably better to err in the other direction and saygetwhenever you meanget. There are no prizes for obfuscated AppleScript, and you're most likely to confuse yourself (and impress no one else) if you get into bad habits. More important, omission ofgetfrom expressions of any complexity can cause runtime errors. For example, this:tell application "Finder" to display dialog (name of folder 1) -- error: Finder got an error: Can't make name of folder 1 into type stringis not the same as this:tell application "Finder" to display dialog (get name of folder 1) -- MannieIn the first example,name of folder 1is a reference to an attribute; that's not something that can be displayed bydisplay dialog, so we get an error. In the second, thegetcommand fetches the value of that attribute, a string, and all is well. AppleScript programmers like to say thatgetresolves references .Sometimes, just the other way around, you don't want references resolved. This works (the first word of the document is deleted):tell application "TextEdit" to delete word 1 of document 1
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - It
- InhaltsvorschauThe keyword
itrepresents the target. (In situations where you would sayof itafter a word, you may sayitsbefore that word instead.)The keyworditcan be useful in helping you understand who the target is. It can also be useful as an explicit target, in situations where AppleScript would otherwise misinterpret your meaning.This example showsitused while debugging, to make sure we understand who the target is:tell application "Finder" tell folders it -- every folder of application "Finder" end tell end tellSometimes when you get yourself deep in a nest of tell blocks (see "The Chain of Ofs and Tells," earlier in this chapter),itcan be helpful for referring to the target one level up. For example, this code opens file 1 of folder 1 and also opens folder 1 itself:tell application "Finder" tell folder 1 open file 1 open it end tell end tellYou have already seen ("Accessing Top-Level Entities" in Chapter 8) the need foritwhen accessing a script object's top-level entities within a tell block addressed to the script object. When targeting an attribute of a scriptable application, there is generally no need foritused in this way. Unlike a script object, an application has a dictionary, so AppleScript knows when you're saying the name of an attribute of that application. For example, the Finder has an attributehome; there is no need foritsto tell AppleScript that we mean the Finder'shomerather than a variable in scope:set home to "Ojai" tell application "Finder" get home -- folder "mattneub" of folder "Users"... end tellIn fact, here the problem is more likely to be how to refer to the variablehomefrom within this tell block. The next section ("Me") solves the problem.However, there is one situation whereitis needed when targeting an application. It may happen that an application's dictionary gives a property (a kind of attribute) and a class the same name. Applications really shouldn't do this, but in fact they do it quite often. WithoutEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Me
- InhaltsvorschauThe keyword
merepresents the current script—the script or script object that is running the code where the keywordmeappears. (In situations where you would sayof meafter a word, you may saymybefore that word instead.) Thus:script myScript me -- «script myScript» end script run myScript me -- «script», the anonymous top-level script parent of me -- «script AppleScript»See also "The Implicit Parent Chain" in Chapter 8.We saw the keywordmeused earlier (Chapter 8) as a way to force AppleScript to interpret a term as belonging to the current script object, so that it will use the inheritance chain.When targeting an application in a tell block,mecan be helpful as a specifying that the target should be your script instead. For example, this doesn't work:on reverseString(s) set text item delimiters to "" return (reverse of characters of s) as string end reverseString tell application "Finder" set name of folder 1 to reverseString(get name of folder 1) -- error: Finder got an error: Can't continue reverseString end tellWhen we come to the handler callreverseString( )in the next-to-last line, the target is the Finder. So AppleScript passes it along to the Finder. The Finder doesn't know what to do with this message. The target forreverseString, and onlyreverseString, needs to be the current script. This is a job forme(a "can't continue" error usually is):set name of folder 1 to my reverseString(get name of folder 1)Butmewon't also resolve a terminology clash between a term defined by the target and a term within your script. In that case, you'll have to use pipes (vertical bars) around the term, to prevent its resolution by the target dictionary. For instance, how might I refer to the global variablehomein a tell block directed at the Finder, which has ahomeattribute? I can try usingmy, but I just get a mysterious error message:set home to "Ojai" tell application "Finder" get my home -- error: Can't make home directory into type referenceEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Properties and Elements
- InhaltsvorschauThe purpose of the chain of
ofs andtells is to navigate a structure formed by objects standing in a relationship of owner and attribute to one another. For example, the phrasefolder 1 of application "Finder"is needed because folder 1 is an attribute of the Finder, and because I can refer directly to the Finder but not to its attributes. Figuring out how to form a chain ofofs andtells that will let you refer successfully to a desired object constitutes much of the effort of AppleScript programming, as Appendix A vividly illustrates. An application's dictionary is supposed to help you with this, though it often falls short (Chapter 20). AppleScript's own dictionary is not typically visible, so later in the book I'll list the attributes of the built-in datatypes (Chapter 13).An attribute is either a property or an element . (In fact, I had to coin the term "attribute" because the official AppleScript documentation lacks any comprehensive term for "property or element.") A property is an attribute that this class of object has exactly one of. An element is an attribute that this class of object may have any number of, and in order to refer to one (or more), you have to say which one(s) you mean.For example, given a list,lengthis a property; every list has a length, and that's the end of that. Butitemis an element; a list might not have any items, and if it does have some, it can have any number of them. To speak of an item or items we have to say which one(s) we mean, as initem 1. Similarly, with regard to a folder in the Finder,nameis a property butfileis an element.Some properties are read-only : you can get but not set their value. For example:tell application "Finder" get startup disk set startup disk to disk "gromit" -- error: Finder got an error: Can't set startup disk to disk "gromit" end tellElements in general are read-only in the sense that you can't say "set folder 1 to" something. However, you can set an element's properties (except those that are read-only, of course), and applications usually implement verbs that permit to you create and manipulate elements.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Element Specifiers
- InhaltsvorschauReferring to a property is easy; you just use the name of the property. For example:
get version of application "Finder" -- 10.4.2Referring to an element is harder. An object can have any number of each class of element, so you must say which one(s) you mean. To do this, you use an element specifier (or just specifier for short—AppleScript also calls this a key form). A specifier has two components: the name of a class and some way of picking out the right one(s). AppleScript has eight built-in forms of specifier, and these are the only ones you are allowed to use. The next eight sections describe those eight specifier forms.(Actually, there are actually nine element specifiers. I don't discussmiddlebecause it is rarely used. Plus, a reference to a property is actually a form of specifier, so I guess that makes ten. The variety of specifier forms makes a specifier quite an interesting and complicated part of an Apple event. The repeated pattern involving the four termsform,want,seld, andfromin Example 3-1 denotes a specifier.)In real life, it will rarely be open to you to use just whichever specifier form you please on a particular occasion. Given a certain application, object, and class of element, only certain specifier forms will work, and experimentation is the best guide as to which ones they are. An application's dictionary is supposed to help you here, but it might not, or might not be accurate (see "Defective Element Specifiers" in Chapter 20).An element may have a name, which is some kind of string. (I say "some kind of" because it might, for example, be Unicode text, which is not the same class as string.) To specify an element by name, say the class followed by the name:tell application "Finder" to get disk "main"
You may insert the keywordnamedbetween the class and the name, but I never do.Typically, there is also anameproperty, so that you can learn, based on some other element specifier, how to specify a particular element by name:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Operations on Multiple References
- InhaltsvorschauWhen an element specifier would return a list of references, it may be possible to ask for an attribute of this list as a shorthand for asking for that attribute of each element of the list in turn; the request to fetch the attribute is applied distributively to each item of the list.For example, this works, and returns a list of strings, the names of each disk in turn:
tell application "Finder" to get name of every disk
Similarly:tell application "iTunes" tell view of browser window 1 get name of every track end tell end tellPossibly you can even apply this construct to the result of a boolean test:tell application "iTunes" tell view of browser window 1 get database ID of every track whose name contains "Palestrina" end tell end tellThose examples illustrate a property; the same thing may work for an element:tell application "Finder" get file 1 of every folder end tellWhen you request multiple elements distributed across a list in this way, whether you get back a list of lists or a single flattened list depends upon the individual application. For example:tell application "Address Book" get every email of every person end tellThe result of that code is a list of lists—the outer list has as many items as there are persons, with each item being a list of every email address of the corresponding person. But when you try something similar in the Finder, the result is a single list of files:tell application "Finder" get every file of every folder end tellAn application may also be willing to accept a list as the direct object of a command, applying the command distributively to each member of the list. You can't know until you try:tell application "Microsoft Entourage" move (every message of in box folder where address of its sender ¬ contains "lambert") to folder "temp" end tellDespite the parentheses inserted by AppleScript's compiler, there's only one Apple event here. You're not getting the list and then sending it back to Entourage for processing: you're describing the list and telling Entourage to construct and process it.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Assignment of Multiple Attributes
- InhaltsvorschauRecall from Chapter 7 that it is possible to assign multiple values in a single command by using a list:
set {x, y, z} to {1, 2, 3}You can use this syntax to fetch multiple attributes , using eithertellorof:tell application "Finder" set {x, y} to {name, comment} of folder 1 end tell {x, y} -- {"Mannie", "howdy"}That code fetchesname of folder 1andcomment of folder 1from the Finder in a single command.You can use this construct to set multiple properties as well, but only in a tell block (trying to do it withofwill cause a runtime error):tell application "Finder" tell folder "Mannie" set {comment, name} to {"zowie", "Jack"} end tell end tellBe careful of the order in which you list the properties when assigning to them. The values are assigned from left to right. This wouldn't have worked:tell application "Finder" tell folder "Mannie" set {name, comment} to {"Jack", "zowie"} -- error end tell end tellThat code sets the name first, and afterwards there is no longer afolder "Mannie"to set the comment of, so the attempt to set thecomment of folder "Mannie"causes a runtime error.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Object String Specifier
- InhaltsvorschauFor certain objects in the "real world" (that is, the real world inside the computer), AppleScript has a bootstrap problem. It needs a way to refer to these objects, yet they are not attributes of anything. In fact, they are the things that have attributes. So in order to talk about anything at all outside of the script, AppleScript must pull itself up by its bootstraps.The solution is an object described using the name of the class followed by a string. It looks rather like an element specifier by name; but the object isn't an element of anything, and the string isn't exactly a name. There is no official term for this construct in Apple's documentation, so I call it an object string specifier . The main real-world objects for which object string specifiers are used are applications, files and aliases, and dates. Details appear in Chapter 13, but here are some examples.Throughout this chapter I've constructed application targets using an object string specifier with the
applicationclass:tell application "BBEdit"
In the case of a file or an alias, the string is a pathname:get POSIX path of file "myDisk:myFile"
The string doesn't have to be a literal; a variable will work just as well:set f to "myDisk:myFile" get POSIX path of file f
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 12: References
- InhaltsvorschauReferences are an important feature of AppleScript, and many values that you'll encounter using AppleScript will be references. A reference is a special type of data. It isn't the actual data; it's more like a pointer to the data. But it isn't a pointer, either; if you're used to pointers or indirect addressing from some other computer language, a reference is something else again. Remember, AppleScript is all about communicating with scriptable applications. In replying to a communication, the scriptable application might hand you a reference. In this context, a reference is a very powerful thing; it's like an Apple event primed and ready to communicate with an object in that application's world. A reference can be a great convenience, or it can be a danger: if you're not careful, you can send that Apple event and tell that scriptable application to do something you never intended. Unfortunately, AppleScript goes to some lengths to make it difficult for you to know that you've got a reference in the first place! This chapter explains what references are and how to know when you've got one. It also shows how to make a reference deliberately, and how to do some powerful things with references.The phrase "by reference," as in "Set by Reference" in Chapter 7 and "Pass by Reference" in Chapter 9, is not what this chapter is about. When you pass a list "by reference" as a parameter to a handler, you do not pass a reference; you pass a list in a certain way. To make things even more complicated, we'll talk about passing a reference as a way to simulate passing by reference! The identity of the terminology is unfortunate but unavoidable.It's hard to explain what a reference is. In a sense, it is simply a complete target , such as
folder 1 of application "Finder". But it isn't the target "out there" in the world; it's the target as expressed in your code. This way of putting it makes a reference sound like merely an expression. But it's more than that. It's a value embodying such an expression.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Reference as Target
- InhaltsvorschauIt's hard to explain what a reference is. In a sense, it is simply a complete target , such as
folder 1 of application "Finder". But it isn't the target "out there" in the world; it's the target as expressed in your code. This way of putting it makes a reference sound like merely an expression. But it's more than that. It's a value embodying such an expression.To see what I mean, let's imagine obtaining such a value in a way that's very common—as a result returned by a scriptable application. Any time you fetch an attribute of a scriptable application, if the result is not a built-in datatype such as a string, it is likely to be a reference. For example:tell application "Finder" set x to (get folder 1) end tellNow, what'sx? On my machine, it's the following:folder "Mannie" of desktop of application "Finder"
It sounds natural enough. But think a little more about this. What can it mean? What isx, really? A folder is a thing in the Finder's world. Surely the Finder cannot have literally handed this folder to our script. Rather, the Finder has handed us a way of talking about this folder, a means of access to this folder. That's a reference.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Reference as Incantation
- InhaltsvorschauOne very productive way to think of a reference is as an incantation . It's like frozen speech. It encapsulates a bit of phraseology, a particular utterance. If a variable's value is a reference, that value is something you can use to access the object it refers to. What I mean by "use" is "say": a reference is an encapsulation of the words you would have to utter (in your code, of course) in order to access the object. In a way, a reference is like a miniature package of suspended evaluation; it's a little phrase that isn't evaluated until you use it. When you do use it, it works just as if you'd said the phrase at that point in your code.For example, consider this code:
tell application "Finder" set x to (get folder 1) display dialog (get name of x) -- Mannie end tellThe dialog shows the name of the folder. Why does this work? As we have said,xis this reference:folder "Mannie" of desktop of application "Finder"
This means that usingxis like using those words. Therefore, when you say this:get name of x
it's just like saying this:get name of folder "Mannie" of desktop of application "Finder"
A reference answers the "What would I have to say?" question. What would I have to say in order to speak of the Finder'sfolder 1? The Finder tells us one answer; I could say this:folder "Mannie" of desktop of application "Finder"
You may be disconcerted at first by that fact that this is not what you did say. You saidfolder 1, referring to the folder by index number; the Finder saidfolder "Mannie", referring to it by name. You didn't sayof desktop; the Finder did. You shouldn't worry about this. You just have to have faith, when an application gives you a reference, that this reference will access the thing you asked for access to.When the time comes to use a reference, you don't have to be in the context of a tell block. The reference is not only a complete target; it's a complete target whose vocabulary hasEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating a Reference
- InhaltsvorschauWe've seen that a reference might be handed to you by some application, but you can also create one yourself. To do so, you use the
a reference tooperator. (An abbreviation isref, which is a lot easier to type. Intermediate abbreviation forms likea refandref toare legal as well.) For example:set x to 100 set y to a reference to x
When you create a reference, the phrase you use is effectively what gets frozen into the reference as an incantation. Thus, in a situation where you would have been handed a reference anyway, asking explicitly for a reference could get you a different reference:tell application "Finder" set x to a reference to folder 1 end tell x -- folder 1 of application "Finder"What you say is what you get. And what you say doesn't have to exist, either—it doesn't even have to make sense! As long as the compiler can resolve the terminology, it will compile your phrase. The fact that it's unusable doesn't matter; you're not using it, you're just freezing it for later. Thus no error arises, no matter how silly your phrase may be. Of course, later on if you do try to use it, you'll find out if it's a valid thing to say at that point:tell application "Finder" set x to a reference to disk 99 of folder 1 of label "yoho" end tell get name of x -- error: Can't get name of disk 99 of folder 1 of label "yoho"What that shows is that asking explicitly for a reference does not send an Apple event; it merely creates the Apple event so you can save it for later.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Identifying References
- InhaltsvorschauAppleScript goes to some lengths to hide the existence of references, making it remarkably difficult to find out that a value is a reference. Properly speaking, a reference should be a class, a datatype like
stringorinteger(see "Class" in Chapter 11, and Chapter 13). If you ask a string about its class, it saysstring. If you ask an integer about its class, it saysinteger. But if you ask a reference about its class, it will never tell the truth and sayreference.set x to a reference to "hey" set y to a reference to 9 tell application "Finder" to set z to folder 1 class of x -- string class of y -- integer class of z -- folder
Here are a couple of tricks you can use to learn that a value is a reference. (I don't guarantee any of them, but they do seem mostly to work.)- The reference coercion trick
-
The only thing that can be coerced to a reference is a reference. If you try to coerce anything else to a reference, you'll get a runtime error. So try to coerce a value to a reference, and if there's no error, it is a reference. For example:
tell application "Finder" to set x to folder 1 x as reference -- no error; it's a reference - The editor value trick
-
If a value, as shown in your script editor application, contains the word
of, it is a reference. For example:tell application "Finder" to set x to folder 1 x -- folder "Mannie" of...; it's a reference set x to a reference to y x -- y of «script»; it's a reference
When I'm debugging or developing a script, I like the second method best; I look at a variable's value and I can usually see right away whether it's likely to be a reference. If I'm writing code where the code itself needs to test whether something is a reference, I like the first method best. Here's a general handler that returns a boolean value telling whether its parameter is a reference:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Dereferencing a Reference
- InhaltsvorschauOnce you have a variable whose value is a reference, AppleScript behaves with confusing inconsistency when you try to use it. In some cases, you can't use the reference unless you explicitly dereference it; in other cases, AppleScript dereferences it for you implicitly when you use it. AppleScript can even behave both ways with one and the same reference.When AppleScript performs implicit dereferencing , the reference is completely transparent; it acts precisely as if you were saying the incantation that's frozen inside it. This is exactly the same phenomenon noted in the previous section—you can't learn from a reference that it is a reference, because it acts as if it were the thing referred to.
tell application "Finder" set x to folder 1 end tell name of x -- Mannie class of x -- folder set name of x to "Moe"None of that ought to be possible. A reference's class isn'tfolder, and a reference doesn't have anameproperty that you can get and set. In this case, though, it happens that the reference is a reference to a thing whose class isfolderand that has anameproperty. AppleScript dereferences the reference implicitly; it treats the reference as if it were the thing referred to.But in this example, an attempt to use the same reference transparently runs up against a brick wall:tell application "Finder" set x to a reference to name of folder 1 end tell set x to "Moe"If you were hoping that this code would set the name of the Finder'sfolder 1to"Moe", you're doomed to disappointment. It didn't: you set the variablexto the string"Moe"(and you lost your reference).The reason is that the transparency of references can't be permitted to destroy your access to your own variables. Thus, when you perform an assignment , not to a property of a variable that's a reference but to the variable itself, AppleScript stops treating the reference transparently. The assignment is an ordinary assignment to a variable; what's inside the shoebox is thrown away and a new value is put into the shoebox.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Trouble with Contents
- InhaltsvorschauA problem arises when you're targeting an application whose dictionary defines a
contentsproperty for one of its object types. Applications shouldn't do this; it's bad behavior, because they're overlapping with a piece of AppleScript's own built-in vocabulary. In the context of a tell block directed at such an application, there is an ambiguity as to whether the wordcontentswill be seen as thecontents ofoperator or the application'scontentsproperty.I'm told that the problematic nature of thecontentsproperty is actually an AppleScript bug. And AppleScript itself is to blame for taking the lead here; it defines acontentsproperty for itsselection-objectclass, luring application developers into doing the same sort of thing.An example of such an offender is BBEdit. In BBEdit, when you ask for a text element such as aword, it gives you a reference rather than a string. That's good, because it's then possible to access that element in its context and do things to it. But then BBEdit does something bad: it defines thecontentsproperty as your way of obtaining the actual string. But it can be quite tricky to get AppleScript to ask BBEdit for thecontentsof something, because it often sees this as an attempt to dereference a reference instead.So this works to obtain an actual string:tell application "BBEdit" set w to contents of word 4 of window 1 end tell w -- "test"But this doesn't:tell application "BBEdit" set w to contents of (get word 4 of window 1) end tell w -- characters 11 thru 14 of text document 1 of application "BBEdit"And therefore neither does this:tell application "BBEdit" set x to word 4 of window 1 set w to contents of x end tell w -- characters 11 thru 14 of text document 1 of application "BBEdit"And of course if you start by asking for a reference, things are even worse:tell application "BBEdit" set x to a reference to word 4 of window 1 set x to contents of x set w to contents of x end tell w --Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating References to Variables
- InhaltsvorschauYou can't make a reference to a local variable. Well, you can, but if you try to use it you'll get a mysterious error. For example:
local x set x to {1, 2, 3} set y to a reference to x get item 1 of y -- error: Can't make item 1 of x into type referenceBut a reference can itself be stored in a local variable:local y set x to {1, 2, 3} set y to a reference to x get item 1 of y -- 1You can make a reference to anything that isn't a local, such as a global or a top-level entity:script myScript property x : 5 set y to a reference to x set contents of y to y + 1 display dialog x end script run myScript -- 6That works just as well from outside of the script object:script myScript property x : 5 display dialog x end script tell myScript set y to a reference to its x set contents of y to y + 1 run -- 6 end tellEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Reference as Parameter
- InhaltsvorschauYou can pass a value that is a reference as a parameter to a handler, and it remains a reference. So, for example:
local x tell application "Finder" set x to folder 1 end tell on setName(theRef) set name of theRef to "Jack" end setName setName(x)That code successfully changes the name of a folder in the Finder.You can pass as a parameter a reference to anything you can usefully make a reference to. Thus, thereference tooperator almost provides a solution to the problem of passing by reference (see Chapter 9):on doubleRef(theRef) set contents of theRef to 2 * theRef end doubleRef script s property x : 5 display dialog x end script doubleRef(a reference to s's x) run s -- 10But this solution is not completely general, and indeed no completely general solution is possible, because you can't usefully make a reference to a local. Also you'll notice that the example worked only because the handlerdoubleRefknew in advance that it was going to be handed a reference—it explicitly dereferenced the reference in order to change the thing referred to. So passing a reference is a way to allow a handler to change a value in place, but this is not the same thing as passing by reference, and it doesn't work if the value to be changed is a local variable.The use of a reference as a parameter can permit a handler to perform dynamic targeting. As long as a handler doesn't use any vocabulary that depends on a specific target, it can target an application whose identity is not known until runtime. In this example, the same code in the same handler is able to target the Finder and Mailsmith indiscriminately:on getNameOfAnything(theRef) return name of theRef end getNameOfAnything tell application "Finder" to set x to folder 1 tell application "Microsoft Entourage" to set y to message 1 of in box folder getNameOfAnything(x) -- "Mannie" getNameOfAnything(y) -- "Order Confirmation"A handler or script object can also return a reference. Of course, this cannot be a reference to a local variable. It must be a reference to something that the handler or script object can obtain a reference to. For example, it can be a reference to a property:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 13: Datatypes
- InhaltsvorschauA datatype is a classification of a value; every value is of one datatype or another. This is what AppleScript calls a class . For example,
stringis a datatype,integeris a datatype, and so forth. AppleScript provides a number of native datatypes; this chapter describes them.Scriptable applications can extend the language through additional classes. For example, the Finder implements afolderclass. But such additional classes are confined to the application that defines them; a value returned by a scriptable application must be either a reference to an object belonging to that application or one of AppleScript's native datatypes .Script objects, handlers, and references are not dealt with in this chapter (see respectively Chapters 8, 9, and 12). The details of coercion, the conversion of certain values from one datatype to another, will be explained in Chapters 14 and 15.The application class is used mainly to specify a target. This, in effect, is the primary act of AppleScript programming. You specify a target so that you can send messages to it, and sending messages to an application is the purpose of AppleScript.You specify an application using an object string specifier —the wordapplicationfollowed by a string representing the application's name or (colon-delimited) pathname. An abbreviation forapplicationisapp. For further details on how to target an application using an application specifier, see "Local Applications" in Chapter 23.The machine class is used to form a machine specifier, which appears in conjunction with an application specifier to target an application running on another computer. See "Remote Applications" in Chapter 23 for further details.The data class represents raw data , a stream of bytes. It's a catch-all for situations when a value cannot be displayed in any other way. For example:tell application "Finder" activate get (the clipboard) end tell --Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Application
- InhaltsvorschauThe application class is used mainly to specify a target. This, in effect, is the primary act of AppleScript programming. You specify a target so that you can send messages to it, and sending messages to an application is the purpose of AppleScript.You specify an application using an object string specifier —the word
applicationfollowed by a string representing the application's name or (colon-delimited) pathname. An abbreviation forapplicationisapp. For further details on how to target an application using an application specifier, see "Local Applications" in Chapter 23.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Machine
- InhaltsvorschauThe machine class is used to form a machine specifier, which appears in conjunction with an application specifier to target an application running on another computer. See "Remote Applications" in Chapter 23 for further details.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Data
- InhaltsvorschauThe data class represents raw data , a stream of bytes. It's a catch-all for situations when a value cannot be displayed in any other way. For example:
tell application "Finder" activate get (the clipboard) end tell -- {«class RECT»:«data RECT0000000000B40075»,¬ picture:«data PICTFA480000000000B40075001102FF0C...»}, and so on for pages and pagesHere we see a record with two items; the value of each item (after the colon) is a data object. What was on the clipboard was a picture, and the Script Editor can't display it (though Script Debugger can), so it shows you the data as a sequence of hex bytes. Evidently what we have is a rectangle (probably the bounds of the picture) and a picture resource in PICT format.It is also possible to form a data object yourself, by typing just the sort of thing you see here: the worddata, a space, and then the resource type and the data, in guillemets (« »). However, this is an advanced technique and shouldn't arise much in real life (though an example of it appears later in this chapter).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Boolean
- InhaltsvorschauA boolean is a datatype consisting of exactly two possible values:
trueandfalse. The main use for a boolean is as a condition in a control statement, such asiforrepeat while(see Chapter 19). It often appears also as a way of setting yes-or-no options in a command; for example, thechoose filecommand (discussed in Chapter 21) lets you submit a boolean to indicate whether invisible files and folders should be displayed. Some common commands, such asexists, return a boolean. AppleScript has a number of operators that generate or combine booleans (listed in Chapter 15).class of true -- boolean class of (1 < 2) -- boolean
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Integer, Real, and Number
- InhaltsvorschauThe integer and real datatypes are the numeric classes. Integers and reals are used for arithmetic calculation (Chapter 15 will discuss AppleScript's operators for this purpose); they are also used, of course, for communicating numeric values between your script and a target application.
class of 1 -- integer class of 1.1 -- real
A literal integer is a series of digits, possibly preceded by a minus sign. The maximum integer is536870911, positive or negative. Any integer value outside this range is implicitly coerced to a real. This is a very strange limit—it's 229-1, two bits short of the four-byte standard—and I don't know the reason for it.A literal real is a series of digits with a decimal point, possibly preceded by a minus sign. You may also use "scientific notation ": that's a number followed by small or capitale, possibly followed by a plus sign or a minus sign, followed by an integer. AppleScript might rewrite a scientific notation number for you, but it remains a real:1e2 -- rewritten: 100.0 2.1e26 -- rewritten: 2.1E+26
A literal number consisting of too many digits (I have not been able to determine exactly how many is too many) may be rounded, or may be rewritten using scientific notation, at compile time. Alternatively, it may generate an incomprehensible error:0.123456789012345 -- Syntax error. some object [sic]You can't include a comma as a thousands separator in a literal number.The classnumberis purely for purposes of coercion. See "Number, String, and Date Coercions" in Chapter 14.A dictionary may occasionally mention a classsmall integer, which is two bytes (ranging from-32768to32767). You can create one by coercion, but there should be little need to do so (though an example appears later in this chapter). Small integers are typically used transparently; they evidently become integers before you get a look at them:set x to 4 as small integer class of x --
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Date
- InhaltsvorschauA date is a date-time. A literal date is an object string specifier . In constructing a date, you may use any string value that can be interpreted as a date, a time, or a date-time; AppleScript (or more probably the system) is quite liberal in what it will accept, provided that the string makes sense in terms of the date and time format settings in your International System Preferences . AppleScript supplies missing values such as today's date (if you give only a time) or this year (if you don't give a year) or midnight (if you give only a date). To form a date object for the current date-time, use the
current datescripting addition command (see Chapter 21).AppleScript presents a literal date specifier in long date-time format in accordance with your International preferences. It does this even within your script, on decompilation, if you use a literal string in a date specifier:date "5/25/2005" -- rewritten: date "Wednesday, May 25, 2005 12:00:00 AM"If the expression"5/25/2005"isn't a date according to your International preferences, this code won't compile. For example, if you have U.K. settings, you'd need to typedate "25/5/2005". Scripts that form dates dynamically by coercing from a string, like most of the examples in this section, are subject to the same caveat (and are thus not very portable).AppleScript knows nothing of time zones , and assumes the Gregorian calendar even for dates before its invention. An attempt to form a date specifier earlier than the start of 1000 AD will fail:set s to "December 25, 800" date s -- date "Monday, December 25, 2800 12:00:00 AM"Confusingly, however, you can obtain such a date by calculation:set s to "December 25, 1000" set d to date s set year of d to 800 d -- date "Monday, December 25, 0800 12:00:00 AM"Internally, a date is stored as a number of seconds; precision higher than a second is thrown away during calculation. There are three ways to do calculations with dates:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - String
- InhaltsvorschauA string is the basic text datatype. It has the MacRoman encoding; see "Unicode Text," later in this chapter, for more about the implications of this. Strings are your primary medium for communicating text information to a scriptable application. AppleScript provides some basic string operators (discussed in Chapter 15).A literal string is delimited by quotation marks:
set s to "howdy" class of s -- stringThe empty string is symbolized by"".In typing a string literal, you may enter certain characters in "escaped " form; they are listed in Table 13-1. These are the only "escaped" characters.Table 13-1: "Escaped" string literals What to typeASCII equivalentResult\"ASCII character 34Quotation marks\tASCII character 9Tab\rASCII character 13Return\nASCII character 10Newline\\ASCII character 92BackslashOther untypeable characters may be generated using theASCII characterscripting addition command and incorporated into a string by concatenation (see chapters 15 and 21). There are also a few global properties expressing character values (listed in Chapter 16); these too can be incorporated into a string by concatenation.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Unicode Text
- InhaltsvorschauLike the Macintosh itself, the AppleScript string class has long been bedeviled by the existence of text encodings representing characters outside its own native encoding, which is MacRoman . With the coming of Mac OS X, this problem is essentially solved at system level: text is now Unicode . Unicode expresses tens of thousands of characters in a single massive encoding, and in its fullest form will express about a million characters, embracing every character of every written language in history. Unfortunately, AppleScript precedes Mac OS X, and the string class is still its primary text class. Over the years, various secondary classes have been fudged into AppleScript in an attempt to increase a string's representational power and to improve AppleScript's compatibility with text in the world around it. At the moment, the most important of these is the Unicode text class, which has the UTF-16 encoding.Text supplied by the system is often Unicode text rather than a string. For example:
tell application "Finder" to set x to (get name of disk 1) class of x -- Unicode textSimilarly, some Mac OS X-native applications, such as TextEdit, return text values as Unicode text.The trouble is that Unicode text remains very much a second-class citizen within AppleScript. Perhaps someday all AppleScript text will be Unicode text, but that day has not yet come. A literal string (the stuff between quotes in your code) is still a string, not Unicode text. Thus, you can't even enter a Unicode string directly; you can try, but non-MacRoman characters are lost at compile time. AppleScript's supplied string manipulation commands, such as the scripting addition commandASCII character, don't work outside the MacRoman range. Thecharacterstring element knows nothing of composed characters. Unicode text display (in a result, for example) isn't particularly good either; many non-MacRoman characters are not displayed properly. Unicode text communication between a script and a Unicode-savvy application works, but problems can arise.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - File and Alias
- InhaltsvorschauA file object is a reference to a file or folder on disk. To construct one, use an object string specifier —the word
filefollowed by a string representing a colon-delimited pathname:file "feathers:Users:mattneub:"
By "colon-delimited" I mean an old-style Macintosh -type path. This is not the same as the new-style Unix-type path (new to Mac users, anyway), also known as a POSIX path. AppleScript has a long history on Macintosh, so it is not surprising that its native representation of file paths is not the Unix representation. Macintosh paths start with a disk name, and the delimiter between the disk name, folder names, and filename is a colon. A pathname ending in a colon is a folder or a disk. (A partial pathname, one whose first element is not a disk, is taken to start inside the "current directory," but the interpretation of this notion is unreliable, and partial pathnames should be avoided.)Oddly, you can't assign a file object specifier to a variable, or return it as a value. If you try, you get a runtime error message:set x to file "feathers:Users:mattneub:" -- error: Can't make file "feathers:Users:mattneub:" into type referenceInstead, you must generate a reference to the file object, like this:set x to a reference to file "feathers:Users:mattneub:" x -- file "feathers:Users:mattneub:" of «script»A file specifier is not resolved until the script actually runs. This means that the item on disk need not exist at compile time. At runtime, however, when the file specifier is handed to some command, either the item must exist, or, if the command proposes to create it, everything in the path must exist except for the last element, the name of the item you're about to create. Otherwise the command will generate a runtime error on the grounds that it can't find or create the item. We've already met one command that accepts a file specifier to create a file—store script(see "Compiled Script Files as Script Objects" in Chapter 8).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - List
- InhaltsvorschauA list is a collection corresponding roughly to what many other languages would call an array—it's an ordered set of values. These values are its items. Each item can be of any datatype (including a list). Lists are returned by scriptable applications from element specifiers such as
everyand boolean tests. They are useful for passing as parameters to commands and handlers because they can contain any number of items. AppleScript provides some operators for testing the contents of a list and for concatenating lists to form a new list (see Chapter 15).A literal list is delimited by curly braces. Its contents can be literal values, variable names, or any other expressions that AppleScript can evaluate meaningfully; they are separated by commas. The literal empty list is just a pair of curly braces:set empty to {} set pep to {"Mannie", "Moe"} set pep3 to "Jack" empty & pep & {pep3} -- {"Mannie", "Moe", "Jack"}You can assign a list of values to a literal list of variable names or other references as a shorthand for performing multiple assignments. The assignments are performed pairwise in order: item 1 to item 1, item 2 to item 2, and so on. If the list of values is too long, the extra values are ignored; if it's too short, there's a runtime error. (See "Assignment and Retrieval" in Chapter 7 and "Assignment of Multiple Attributes" in Chapter 11.) For example:tell application "Finder" set L to {name of folder 1, name of folder 2} set {oldname1, oldname2} to L set {name of folder 1, name of folder 2} to {"f1", "f2"} end tellWhen you useset(as opposed tocopy) to set a variable to a value that is a list , you set the variable by reference. This means that the list is not copied; the variable's name becomes a new name for the list, in addition to any names for the list that may already exist. The same is true when a list is passed as a parameter to a handler. This special treatment is in common between lists, records, dates, and script objects, the four datatypes that can be mutated in place. (See "Set by Reference" in Chapter 7 and "Pass by Reference" in Chapter 9.) For example:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Record
- InhaltsvorschauA record is an unordered collection of name-value pairs. Each value may be of any type. Records are passed to a few important commands, such as
make, and are returned by scriptable applications and scripting additions as a way of providing a "table" of information (see Chapter 21). They are useful for passing as parameters to handlers because they can contain any number of items. AppleScript provides some operators for testing the contents of a record and for concatenating records to form a new record (see Chapter 15).A literal record looks like a literal list except that each item has a name. The name is separated from the corresponding value with a colon:set R to {who:"Matt", town:"Ojai"}There is no empty record as distinct from the empty list; the empty list is treated as the empty record for purposes of containment and concatenation. A record has noitemelements, its items cannot be referred to by index number, and you can't talk about thebeginningorendof a record.You can assign a record of values to a literal record of variable names or other references as a shorthand for performing multiple assignment. The assignments are performed pairwise by name, independently. If the record of values includes names that aren't in the record of variables, the extra values are ignored; if it's missing any names that are in the record of variables, there's a runtime error. See "List," earlier in this chapter. For example:local who, town set {who:who, town:town} to {town:"Ojai", who:"Matt"} {who, town} -- {"Matt", "Ojai"}When you useset(as opposed tocopy) to set a variable to a value that is a record, you set the variable by reference. This means that the record is not copied; the variable's name becomes a new name for the record, in addition to any names for the record that may already exist. The same is true when a record is passed as a parameter to a handler. This special treatment is in common between lists, records, dates, and script objects, the four datatypes that can be mutated in place. (See "Set by Reference" in Chapter 7 and "Pass by Reference" in Chapter 9.) For example:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 14: Coercions
- InhaltsvorschauA coercion is a conversion of a value of one datatype to a value of another datatype. In AppleScript, not just any old value can be turned into a value of just any old datatype. To put it more strictly: for some pairs of datatype, call them Datatype A and Datatype B, it is the case that at least some values of Datatype A can be coerced to a value of Datatype B. For example, the string
"30"can be coerced to a number; when that happens, you get the number30. There are other strings that can be coerced to other numbers, and there are strings that can't be coerced to any number at all. This implies that there is some sort of equivalence or formula that determines the new value given the old value. This chapter presents these equivalences for every pair of datatypes, describing what coercions are possible and the rules by which they are performed.The discussion is confined almost entirely to AppleScript's native datatypes (listed in Chapter 13). Coercions between these datatypes are defined by the language. Coercions between nonnative datatypes, or between a native datatype and a nonnative datatype, must be implemented by the application that defines the nonnative type. Applications do this, if they do it at all, on an individual basis, so no documentation is possible here. Additional coercions of native (and other) types can be implemented by scripting additions (Chapter 21), but these are not discussed here either.Implicit coercion is performed automatically when you supply a value where a value of another datatype is expected. This happens only in connection with AppleScript's operators. These operators have definite rules about what datatypes they expect, and what implicit coercions they will perform if other datatypes are provided. Details appear in Chapter 15.Otherwise, AppleScript has no implicit coercion .No implicit coercion takes place when assigning a value to a variable, because variables have no declared datatype; the variable simply adopts the new value.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Implicit Coercion
- InhaltsvorschauImplicit coercion is performed automatically when you supply a value where a value of another datatype is expected. This happens only in connection with AppleScript's operators. These operators have definite rules about what datatypes they expect, and what implicit coercions they will perform if other datatypes are provided. Details appear in Chapter 15.Otherwise, AppleScript has no implicit coercion .No implicit coercion takes place when assigning a value to a variable, because variables have no declared datatype; the variable simply adopts the new value.No implicit coercion takes place when a parameter is passed to a user handler, because such handlers are not protected by any mechanism such as prototypes or datatype declarations in their definition from receiving parameters with undesirable datatypes. If your handler has reason to be choosy about what sorts of values it's willing to accept, then it needs to test those values and respond accordingly. For example, it might coerce explicitly, or it might throw an error, like this:
on sendMeAString(s) if {class of s} is not in {string, Unicode text} then error "Can't make some data into the expected type." end if -- remaining code goes here, secure in the knowledge that s is a string... end sendMeAStringCoercion might take place when passing a parameter to a command, but then the coercion is probably not being performed by AppleScript, and whether it is implicit becomes a moot point. For example:tell application "Finder" set sidebar width of window 1 to "123" end tellYou shouldn't have done that, but it works anyway. Thesidebar widthproperty is distinctly said, in the Finder's dictionary, to be an integer. You provided a string, but the Finder, instead of complaining, coerced it to an integer. This has nothing whatsoever to do with AppleScript itself! AppleScript did not look in the Finder's dictionary, see that the Finder expects an integer, and implicitly coerce the string. It sent the string to the Finder, and let you take your chances. You gambled, and luckily, this time, you won.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Explicit Coercion
- InhaltsvorschauExplicit coercion is performed with the
asoperator. There are actually two cases, depending on whether the value to be coerced is a native AppleScript datatype and belongs to your script. These two cases amount to two different operators, even though AppleScript (in its usual misguided attempt to make things "easy") makes them look the same.ascoercioncoercionSyntaxvalue as class
DescriptionIf value is a native datatype, you're asking AppleScript to coerce it to class. If this is a coercion AppleScript is willing to perform, the result is a new value of the requested datatype. If not, there's a runtime error.get... ascoercion by targetcoercion by targetSyntax[get]reference as class
DescriptionIf reference is an object or attribute of some application, you're asking that application to fetch it and coerce it to class. If the application is willing, the result is a value of the requested datatype. If not, there's a runtime error.Coercion by AppleScript is the subject of this chapter, which tells you what coercions AppleScript is willing to perform. For example:9 as string -- "9" 9 as boolean -- error: Can't make 9 into type boolean
Even though a variable's value can be a class, you can't use a variable as the second operand in a coercion. This won't even compile:set className to string 9 as className -- compile-time error: Expected class name but found identifierEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Boolean Coercions
- InhaltsvorschauA boolean may be coerced to a string; depending on whether the boolean is
trueorfalse, this string will be either"true"or"false".A string may be coerced to a boolean . The string"true"(not case-sensitive) will betrue; any other string will befalse.A boolean may be coerced to an integer ; depending on whether the boolean istrueorfalse, this integer will be either1or0.The integers1and0may be coerced to a boolean, yieldingtrueandfalserespectively; other integers can't be coerced to a boolean.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Number, String, and Date Coercions
- InhaltsvorschauAn integer may be coerced to a real .A real (within in the integer range) may be coerced to an integer; it is rounded to the nearest integer. This was a new feature starting in Panther; in earlier versions of AppleScript, a real could be coerced to an integer only if it was an integer (that is, it had no fractional part). The old behavior is still present in
repeat with(see Chapter 19) and, as you'll see in a moment, in coercion from a string (I regard this as a bug).Observe that AppleScript's real-to-integer coercion rule is not like that of other computer languages you may know, such as in C, where the fractional part is thrown away. To throw away the fractional part ofx, sayx div 1(see Chapter 15). Theroundscripting addition command can also help here (see "Numbers and Dates" in Chapter 21), as it can be used to dictate the desired rounding behavior.A number may be coerced to a string.A string may be coerced to a number, provided that the string looks like a literal number; whitespace will be ignored, but nothing else will be. So for example"1a"can't be coerced to a number. But the empty string, or a string consisting solely of whitespace, will be coerced to0.Distinguish between the classesintegerandreal, on the one hand, andnumberon the other. A string may be coerced to a real, provided that the string looks like a number. A string may be coerced to an integer, though, only if the string looks like an integer value:"1.1" as real -- 1.1 "1" as real -- 1.0 "1.0" as integer -- 1 "1.1" as integer -- error: Can't make "1.1" into type integer
But a string that looks like an integer or a real can be coerced to a number, and it will be coerced to whichever datatype is appropriate—integer or real. This is nice because it saves you from having to worry about which is appropriate.class of ("1" as number) -- integer class of ("1.1" as number) -- realEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - File Coercions
- InhaltsvorschauThe various coercions and other forms of conversion that are and are not possible between a file specifier, a POSIX file (file URL ), an alias , and a string or Unicode text (which might represent a Macintosh pathname or a POSIX pathname), are enough to make your head swim. The trouble is that there are many things you can't do; at the same time, there's always a workaround if you're willing to jump through hoops.A Macintosh pathname string can be used to form a file specifier or alias. (A file specifier cannot be assigned to a variable or displayed as a result, but a reference to it can be.) A POSIX pathname string can be used to form a POSIX file specifier. (See Chapter 13.) As I pointed out earlier in the chapter, these are not coercions.An alias can be coerced to a string representing its Macintosh pathname, and its
POSIX pathproperty is a string representing its POSIX pathname. An alias cannot be coerced to a file object, but a string can be used as an intermediary to form a file specifier:set a to alias "gromit:Users:matt2:reason:Resources:" POSIX path of a -- "/Volumes/gromit/Users/matt2/reason/Resources/" a as string -- "gromit:Users:matt2:reason:Resources:" a reference to file (a as string) -- file "gromit:Users:matt2:reason:Resources:" of «script»
A Macintosh pathname can be coerced to an alias. (The item denoted by the pathname must exist at runtime; see Chapter 13.)set s to "gromit:Users:matt2:reason:Resources:" s as alias -- alias "gromit:Users:matt2:reason:Resources:"A file object cannot be coerced to a string. But a file object can be coerced to an alias (though in the Panther version of Script Editor there's a bug that makes it appear that it can't be), which in turn can be coerced to a string. A file object'sPOSIX pathproperty is a string representing its POSIX pathname.set f to a reference to file "gromit:Users:matt2:reason:Resources:" f as alias --
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - List Coercions
- InhaltsvorschauAnything may be coerced to a list . How it is treated depends on what you start with:
- A list
-
The result is identically the same list.
- A record
-
The result is a list of the values from the record:
set R to {name:"Matt", age:51} R as list -- {"Matt", 51} - Anything else
-
The result is a list of one item, that item being the thing you started with.
Coercion to a list is very useful for making sure you have a list; if the thing you start with isn't a list, it becomes one, and if it is a list, it is unchanged. Recall, however, that this coercion might not work if the thing you start with belongs to an application, because that application might not implement it (see "Coercion by a Scriptable Application," earlier in this chapter).Officially you can't coerce a list to a record, but there's a trick for doing it using a second level of evaluation. (Consider the warnings at "Second-Level Evaluation" in Chapter 19 before resorting to this trick; it involves a lot of overhead.) The value of every odd item of the list (which should be a string) becomes the name of a record item, whose value in turn is the corresponding even item of the list:on listToRecord(L) script myScript return {«class usrf»:L} end script return run script myScript end listToRecord set R to listToRecord({"name", "haha", "age", 51}) R -- {|name|:"haha", age:51}To understand the trickery involved here, see "Record" in Chapter 13. Observe that because we are forming a user record, the termnameends up in pipes; it is not the predefinednameproperty, and its value cannot be accessed without pipes around the termname.A list of one item may be coerced to the datatype of that item, and the result will be that item. Of course, the result can then be coerced to any datatype that it can be coerced to, so you can also coerce a list of one item to that datatype in a single step. For example:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Unit Conversions
- InhaltsvorschauAppleScript provides a number of classes whose sole purpose is to allow you to perform measurement unit conversions. They are implemented as classes so that you can use the
asoperator to perform the conversion; that is, the conversion is really a coercion.Because of this implementation, the way you have to speak in order to perform a conversion ends up looking fairly silly. You can't say3 feet; you have to coerce3(a number) to thefeetclass, by saying3 as feet. Now you coerce to the desired class; suppose this isyards. But now you have a value of theyardsclass. You can't do anything with it, so you have to coerce it to a number (or a string). So, for example:on feetToYards(ft) return ft as feet as yards as number end feetToYards feetToYards(3) -- 1.0The implemented units are themselves a mixed lot. Many important units, such as acres and hectares, aren't implemented at all. Accuracy of some of the conversions has also been called into question, but this is said to be fixed in Tiger. Table 14-1 provides a list.Table 14-1: Conversion unit classes metersinchesfeetyardsmileskilometerscentimeterssquare meterssquare feetsquare yardssquare milessquare kilometerslitersgallonsquartscubic meterscubic centimeterscubic feetEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 15: Operators
- InhaltsvorschauAn operator is a token that transforms a value or a pair of values to produce a new value. These transformations are operations, and the values operated upon are the operands. An operator with two operands is binary; an operator with one operand is unary. This chapter lists the AppleScript operators and explains what they do, with special attention to implicit coercions performed by the operators. It also talks about parentheses, because they help determine the effects of the operators. Finally, there's a section on the differences between what happens when AppleScript performs an operation and when a scriptable application performs it.(For the coercion operator,
as, see Chapter 14; for the object containment operator,of, see Chapter 11.)In Chapter 14, I explained coercion and described the coercions that are possible between built-in datatypes in the AppleScript language. Binary operators can (and will) perform coercion without your specifically asking for it. This is called implicit coercion , and is one of the most confusing aspects of AppleScript—and a frequent source of mistakes in scripts. If you are not prepared for what implicit coercions an operator will perform, you will be surprised when the result of an operation is not what you expected. That's why this chapter spends so much time on the implicit coercions performed by the various operators.What coercions AppleScript will perform implicitly is not the same as what coercions you can get it to perform explicitly (with theasoperator). AppleScript's error messages in this regard can add to the confusion. For example:1 and 1 -- compile-time error: Can't make 1 into type booleanThat error message, on its face, is lying. AppleScript can make 1 into a boolean. What AppleScript really means by the error message here is: "In order for me to perform this operation, I would need to coerce the first1(before theand) to a boolean, implicitly; and I refuse to do that." Even weirder is what happens when you proceed to coerce the firstEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Implicit Coercion
- InhaltsvorschauIn Chapter 14, I explained coercion and described the coercions that are possible between built-in datatypes in the AppleScript language. Binary operators can (and will) perform coercion without your specifically asking for it. This is called implicit coercion , and is one of the most confusing aspects of AppleScript—and a frequent source of mistakes in scripts. If you are not prepared for what implicit coercions an operator will perform, you will be surprised when the result of an operation is not what you expected. That's why this chapter spends so much time on the implicit coercions performed by the various operators.What coercions AppleScript will perform implicitly is not the same as what coercions you can get it to perform explicitly (with the
asoperator). AppleScript's error messages in this regard can add to the confusion. For example:1 and 1 -- compile-time error: Can't make 1 into type booleanThat error message, on its face, is lying. AppleScript can make 1 into a boolean. What AppleScript really means by the error message here is: "In order for me to perform this operation, I would need to coerce the first1(before theand) to a boolean, implicitly; and I refuse to do that." Even weirder is what happens when you proceed to coerce the first1to a boolean explicitly:1 as boolean and 1 -- trueIt works—which means that even though AppleScript refused to coerce the first1to a boolean implicitly, it now happily coerces the second1to a boolean implicitly!But do not imagine that there is some simple rule governing this behavior (such as that AppleScript never coerces the first operand implicitly). In this next example, AppleScript happily coerces both operands implicitly (to a number ):"3" + "4" -- 7You see now why the rules for implicit coercion need to be made explicit.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Arithmetic Operators
- InhaltsvorschauThe arithmetic operators combine numbers to get new numbers in accordance with the usual rules of arithmetic. As in most computer languages, multiplication and division take precedence over addition and subtraction (in the absence of parentheses). So, for example:
3 + 4 * 2 -- 11 3 * 4 + 2 -- 14
An operand that is a list consisting of one number will be coerced to a number. An operand that is a string representing a number, or a list consisting of one such string, will be coerced to a number.The class of the result of the addition, subtraction, multiplication, and remainder operators is as follows: the result is an integer if the first operand is an integer and if the second operand either is an integer or is a real that can be coerced to an integer without loss of information. Otherwise, the result is a real.If you have some programming experience and you know a language such as C or LISP (where if either arithmetic operand is a real, the result is a real), you're going to find AppleScript's behavior surprising. Think of it like this. For the result to be a real, it is not enough that one operand be a real; the first operand must be a real, or else the second operand must have a significant fractional part, not merely a decimal point. Sayingx * 1.0, for example, is not a way of making sure you've got a real. When in doubt, coerce explicitly.Do not blame AppleScript for the phenomena inherent in doing floating-point arithmetic in any language on any computer. It is the nature of computer numerics that most values can only be approximated. Modern processors are extraordinarily clever about compensating, but rounding operations can easily expose the truth:2.32 * 100.0 div 1 -- 231Similarly, there may be situations where instead of comparing two values for absolute equality, you will do better to test whether the difference between them lies within some acceptable small epsilon.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Boolean Operators
- InhaltsvorschauThe boolean operators implement the basics of logic, working on boolean operands to produce a boolean result. The second operand, but not the first, will be coerced from a string or an integer, or a list of one string or one integer, to a boolean. Either operand will be coerced from a list of one boolean to a boolean.andlogical andlogical andSyntax
boolean1 and boolean2
DescriptionReturnstrueif both operands are true. If the first operand is false, the second operand won't even be evaluated ("short-circuiting").orlogical orlogical orSyntaxboolean1 or boolean2
DescriptionReturnsfalseif both operands are false. If the first operand is true, the second operand won't even be evaluated ("short-circuiting").notlogical notlogical notSyntaxnot booleanDescriptionChanges true to false and false to true.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Comparison Operators
- InhaltsvorschauThe comparison operators test whether one operand is the same as the other, or whether, if they can be ordered, they are ordered in a given direction. The result is a boolean.The nature of comparisons involving strings can be influenced by a
consideringclause; see Chapter 19.Lists are internally ordered, but records are not:{1, 2} = {2, 1} -- false {name:"Matt", age:"51"} = {age:"51", name:"Matt"} -- trueThe equality (=) and inequality (≠) operators do not coerce their operands; operands may be of any datatype, and operands of different datatypes are unequal. So:{"2"} = 2 -- falseIn that example, the first operand is a list, the second operand is a number, and no coercion takes place. So the operands are not equal, and the comparison is false.With the other comparison operators , operands must ultimately be a string, a number, or a date. The first operator is coerced to a string, a number, or a date, and then the second operator is coerced to match the datatype of the first:{"2"} ≥ 2 -- trueIn that example, the first operand is a list of one string, so it is coerced to a string. Now the second operand is coerced to a string; the two strings are equal and the comparison is true.Thus, although you cannot use the equality operator to learn whether two values would be equal if implicitly coerced to the same datatype, you can work around the problem like this:{"2"} ≤ 2 and {"2"} ≥ 2 -- trueAs noted in "Assignment and Retrieval" in Chapter 7, the equality operator is not overloaded as an assignment operator. This code will compile and run, but it won't assign4tox(it will report whether they are equal):x = 4
= (is)equalityequalitySyntaxoperand1 = operand2
DescriptionEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Containment Operators
- InhaltsvorschauThe containment operators test whether the value of one thing is to be found "inside" the value of another. For example, the string
"test"contains the string"e". Containment may apply to two strings, two lists, or two records. The result is a boolean.Containment implies comparison, and the nature of comparisons involving strings can be influenced by aconsideringclause; see Chapter 19.It is worth stressing that in the case of list containment, both operands must be lists. In other words, the second operand is not an element; it's a sublist. This is a little counterintuitive at first. To complicate matters, AppleScript fools you by apparently letting you say just what you (wrongly) think you should be allowed to say:{1, 2} contains 2 -- trueYou can say that, but not because it is correct on its face; it's because2is coerced to{2}implicitly to get the right syntax, which would be this:{1, 2} contains {2} -- trueBecause the second operand is a sublist, you can ask about more than one element at once:{1, 2, 3} contains {2, 3} -- trueLists are ordered, so the items of the sublist you ask about must appear consecutively and in the same order in the target list. These are false:{1, 2, 3} contains {1, 3} -- false {1, 2, 3} contains {3, 2} -- falseBecause lists can contain lists, you may have to use an explicit extra level to say what you mean:{{1}, {2}} contains {2} -- false {{1}, {2}} contains {{2}} -- trueThe first is false because2is not an element of the first list, and{2}is not going to be coerced to{{2}}for you—it's a list already, so there's nothing to coerce.With regard to record containment, both the label and the value must match for containment to be true:{name:"Matt", age:"51"} contains {name:"Matt"} -- true {name:"Matt", age:"51"} contains {title:"Matt"} -- false {name:"Matt", age:"51"} contains {name:"Socrates"} -- falseRecords are not internally ordered:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Concatenation Operator
- InhaltsvorschauConcatenation is the joining of two things in sequence. It may be performed on a pair of strings (resulting in a string), a pair of lists (resulting in a list), or a pair of records (resulting in a record). Implicit coercions are performed in exactly the same way as for the containment operators (see the previous section). So, for example:
"three" & 20 -- "three20" 3 & "twenty" -- {3, "twenty"}
That example shows the difference the order of operands can make; the reason is perfectly obvious if you know the implicit coercion rules, and baffling otherwise.In earlier versions of AppleScript, concatenation of Unicode text and a string was troublesome, because the class of the result depended the class of the first operand. Now (starting in Tiger), if either operand is Unicode text, the result is Unicode text. This behavior makes string concatenation effectively transparent.To turn string concatenation into list concatenation, it suffices to coerce the first operand to a list ; this can be done simply by expressing it in list delimiters:{"Mannie"} & "Moe" & "Jack" -- {"Mannie", "Moe", "Jack"}Without the list delimiters, we'd end up with"MannieMoeJack".Recall (from Chapter 14) that coercion of a list to a string is another way to concatenate. Thus concatenation of a string and a list concatenates the string with all the elements of the list, each coerced to a string and joined by thetext item delimiters:set text item delimiters to "" "butter" & {"field", 8} -- "butterfield8"Recall what was said in the previous section about both operands having to be of the same type, and what this implies for lists. Concatenation is a way to append one or more items to a list:{1, 2, 3} & {4, 5, 6} -- {1, 2, 3, 4, 5, 6}The result is not{1, 2, 3, {4, 5, 6}}; if that's what you wanted, you can use an extra level of list delimiters:{1, 2, 3} & {{4, 5, 6}}Concatenation of a list to the empty list yields exactly the same list, not a copy. This is probably intended as an optimization, but you are more likely to experience it as a bug. For example:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Parentheses
- InhaltsvorschauParentheses may be used to determine the order of operations at runtime:
3 + 4 * 2 -- 11 (3 + 4) * 2 -- 14
Parentheses can also help determine the order of interpretation of vocabulary at compile time. Thus they can make the difference between successful compilation and failed compilation. For example, this compiles fine, because all the expressions are legal:set r to random number round r rounding up
Now try to save a line by combining them, and you get this ungrammatical and mysterious error:round random number rounding up -- compile-time error: A application constant [sic] or consideration can't go after this identifierThe problem is thatrandom numberis a command that can optionally take various labeled parameters, androunding upisn't one of them. Instead of rethinking its interpretation ("So, mayberandom numberisn't taking any parameters here!"), AppleScript just gives up. You have to help it out, by using parentheses:round (random number) rounding up
Sometimes AppleScript will insert parentheses for you, on compilation. For example, I didn't put any parentheses when I typed this code:tell application "System Events" copy name of every process where it is frontmost to theProc end tellBut AppleScript did, when it compiled:tell application "System Events" copy (name of every process where it is frontmost) to theProc end tellThe reason seems to be to delimit a phrase implying agetcommand. But if you actually usegetexplicitly here without parentheses, AppleScript refuses to compile at all:tell application "System Events" copy get name of every process where it is frontmost to theProc -- compile-time error: Expected "into", "to", etc. but found "get" end tellThe problem seems to be that AppleScript doesn't like the phrasecopy get, which is two commands in a row. If you add the parentheses, AppleScript compiles:tell application "System Events" copy (get name of every process where it is frontmost) to theProc end tellEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Who Performs an Operation
- InhaltsvorschauSome operations within an interapplication communications context can be performed by the target application rather than by AppleScript. There are two cases to consider. The operation may appear as a bare expression (for example, the condition in an
ifclause); I will call this a direct operation . Or, the operation may be part of a boolean test element specifier.According to Apple's documentation, if the first operand of a direct operation is a reference to an object of the target application, the target application should perform the operation. So, for example:tell application "Finder" if name of folder 1 contains "e" thenThe objectname of folder 1is a Finder object, so in this case, according to Apple, the Finder should perform the operation. However, experimentation shows that the Finder does not perform the operation; AppleScript does try to get it to do so, but the target application replies with an error indicating that it doesn't wish to perform that sort of operation. AppleScript thereupon adopts a new strategy: it asks the target application for the values in question, and performs the operation itself.So, here's how that example really works. AppleScript starts by sending the Finder a single Apple event that means: "Please tell me whether the name of your folder 1 contains"e"." The Finder replies with an error message. So then AppleScript tries the other strategy: it goes back to the Finder and sends it another Apple event that means: "Okay, never mind that, just tell me the name of your folder 1." The Finder complies, and now AppleScript looks, itself, to see whether the result contains"e".This approach seems wasteful, but it is wasteful only the first time. The second time the same sort of code is encountered, the AppleScript scripting component remembers that the Finder doesn't do this sort of operation, and skips the first step; it just asks the Finder for the value of the operand and does the operation itself.In fact, I have not foundEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 16: Global Properties
- InhaltsvorschauAppleScript's global properties are essentially predefined variables; they are named values that exist automatically, without your code having to define them. Your code can access them because they are in scope in every script, thanks to the inheritance mechanism (see "Inheritance" in Chapter 8). Your script as a whole is a script object whose parent, by default, is another script object called
AppleScript, which represents the AppleScript scripting component instance. These predefined variables are properties of theAppleScriptscript object. Thus the inheritance mechanism makes them global; no matter where you are when you access one of them, it is sought as a top-level entity up the parent chain until theAppleScriptscript object is reached. Even if the name of a global property is overshadowed in some scope of your script, it can still be accessed through the nameAppleScript. For example:property pi : 3 AppleScript's pi -- 3.14159265359The global properties are like any other script properties, and as such:-
They are settable.
-
Their values are shared by all scripts running under this instance of the AppleScript scripting component.
-
They persist along with this instance of the AppleScript scripting component.
The status of the global script properties is thus somewhat counterintuitive. You might have thought values such aspiandtabwould remain constant. That's not the case. You can change the value of one of them, and then this script and any other scripts that run under the same AppleScript scripting component instance will share this new value. This mechanism introduces a certain fragility, because if a script assumes that these properties always have their default values, it can break. The only thing standing between you, the programmer, and this fragility is a sort of tacit agreement about which global script properties it is customary to change. It is common practice to change the value of theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Strings
- Inhaltsvorschaureturn"\r""\r"Macintosh line-break character. There does not seem to be any conflict with the keyword
return(see "Returned Value" in Chapter 9). The only place where a conflict could occur is whenreturnis the first word of a line. The rule in that situation seems to be that ifreturnis followed by an operator, it can't be the keyword, so it must be this property.Example"This is a line." & return & "This is another line."
tab"\t""\t"Tab character.Example"an item" & tab & "another item"
quote"\"""\""Quote character. (This is new in Tiger.)Examplequote & "This is cool," & quote & " said Tom frigidly."
space" "" "Space character.Example"word" & space & "otherWord"
text item delimiters"" (the empty string)"" (the empty string)Thetext item delimitersglobal property has two uses: it is used to split a string into itstext itemelements (see "String" in Chapter 13), and it is used to join list items when a list is coerced to a string (see "List Coercions" in Chapter 14). In theory it is a list of strings, but in fact it can be set to a string, and if it is a list, only the first item of the list matters.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Numbers
- InhaltsvorschauThe
minutesproperty and its ilk are intended to help you convert to seconds. This is because date arithmetic uses seconds (see "Date" in Chapter 13 and "Arithmetic Operators" in Chapter 15).pi3.141592653593.14159265359The ratio of a circle's circumference to its diameter.Exampleset area to pi * (radius ^ 2)
minutes6060The number of seconds in a minute.Example(current date) + 30 * minutes -- half an hour from nowhours36003600The number of seconds in an hour.Example(current date) + 2 * hours -- two hours from nowdays8640086400The number of seconds in a day.Example(current date) + 2 * days -- two days from nowweeks604800604800The number of seconds in a week.Example(current date) + 2 * weeks -- two weeks from nowEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Miscellaneous
- Inhaltsvorschauversion"1.10.3""1.10.3"The version of AppleScript. The name of this property is also the name of a class, and the appearance that its value is a string is an illusion; this value is actually a version, which is coerced to a string for display.Example
display dialog AppleScript's version -- "1.10.3" AppleScript's version as real -- 1.1003
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 17: Constants
- InhaltsvorschauA constant in AppleScript is a term that functions as a value. It isn't a variable, which is a name that has a value. A constant is a value. The fixed value of a constant will appear to you as the name of the constant. For example, the value of
yesisyes; it cannot be reduced to any other form (though a constant can be coerced to a string). You can use it as a value, but that's about all you can do with it. You cannot set the value of a constant; if you try, you'll get a compile-time error, "Access not allowed." You cannot create a variable whose name is that of a constant; if you try, you'll get a compile-time error, "Expected variable name or property but found application constant or consideration." The datatype (class) of a constant is usuallyconstant; but as we shall see, some of them are aclassinstead.Behind the scenes, many constants are implemented as enumerations, meaning a set of fixed values (called enumerators), any of which may occupy a certain syntactic slot. For example, thereplacingclause of thestore scriptcommand (see "Compiled Script Files as Script Objects" in Chapter 8) may consist of any of the constantsyes,no, orask. Nothing stops you, however, from supplying some other value, in which case it is up to the target to decide how it wants to respond. If you sayreplacing 42in astore scriptcommand, the script will compile and run. If you try to set a date'sweekdaytoyes, the script will compile but not run.Applications are free to extend AppleScript's vocabulary by implementing constants of their own. For example, GraphicConverter can save an image file in many formats, and it needs a way to let you specify a format; it does this with some four dozen constants, such asPICT,TIFF,GIF,BMP, andJPEG. An application's dictionary will show you the constants that can be used in any connection with a given command. See "Enumerations" in Chapter 20.true, falseEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 18: Commands
- InhaltsvorschauA command is basically a verb. Technically, a command is called an event (because it really is an Apple event, as discussed in Chapter 3). This chapter catalogues the built-in commands of the AppleScript language—those not described elsewhere in this book. AppleScript defines very few commands of its own, leaving it to other applications to extend the language by defining further verbs as necessary.(For the syntax of a command, see "Event Handlers" in Chapter 9; on how to use a command, see Chapter 11. For
set,copy, andget, see "Assignment and Retrieval" in Chapter 7. Forrun, see "Run Handler" in Chapter 8. Forerror, see "Errors" in Chapter 19.)A few commands may be sent to applications to start them up, bring them to the front, and make them quit. An application does not have to be scriptable to obey them (see Table 20-1 and the discussion there).launchSyntaxlaunch applicationDescriptionMakes sure an application is running, without bringing it frontmost or making it perform any actions. This command is not commonly needed, because AppleScript, as it runs a script that targets an application locally, will automatically attempt to start up that application if it isn't running already (a good thing, since an application that isn't running can't receive any Apple events). Some applications, however, perform special actions when started up automatically in this way, such as opening a document or coming to the front. Thelaunchcommand can be a way of running the application while avoiding these special actions, and there is no penalty for issuing it if the application is already running, as nothing will happen.activateSyntaxactivate applicationDescriptionEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Application Commands
- InhaltsvorschauA few commands may be sent to applications to start them up, bring them to the front, and make them quit. An application does not have to be scriptable to obey them (see Table 20-1 and the discussion there).launchSyntax
launch applicationDescriptionMakes sure an application is running, without bringing it frontmost or making it perform any actions. This command is not commonly needed, because AppleScript, as it runs a script that targets an application locally, will automatically attempt to start up that application if it isn't running already (a good thing, since an application that isn't running can't receive any Apple events). Some applications, however, perform special actions when started up automatically in this way, such as opening a document or coming to the front. Thelaunchcommand can be a way of running the application while avoiding these special actions, and there is no penalty for issuing it if the application is already running, as nothing will happen.activateSyntaxactivate applicationDescriptionBrings an application frontmost.reopenSyntaxreopen applicationDescriptionTells an application to behave as if it had been opened from the Finder. Some applications behave specially when told to do this. For example, in the case of the Finder,reopenmakes a window open if no Finder windows are open at that moment;launchandactivatedon't.quitSyntaxquit applicationDescriptionEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Standard Commands
- InhaltsvorschauThe standard commands are basic events that should be implemented by any scriptable application. The only standard command implemented by AppleScript itself is
count(with strings, lists, and records; see Chapter 13).countSyntaxcount object[each class] count every class of object count class-plural of object
DescriptionReports the number of class elements of object.Thecountcommand is implemented in an unusual way. The class represents the element that is to be counted; it is optional, and most users prefer the second or third formulation if it is to be specified. (So, one tends to say "count items of L" rather than "count L each item.") If it is not specified, then it is up to the target to supply a default element and count it. Users tend to be unconscious of this fact. For example, when you say "count s," wheresis a string, you're probably not aware that AppleScript is reinterpreting this as "count s each character." That's becausecharacteris the default element for a string; you could also specify a different element ("count words of s"). This syntax is sometimes the cause of misunderstandings, especially when talking to some scriptable application. See "Repeat With... In" in Chapter 19.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Logging Commands
- InhaltsvorschauThese commands have to do with the script editor application's logging window or pane. They control the generation of the AppleScript messages that this window or pane is "watching" while it is open.logSyntax
log valueDescriptionIf the event log pane or window is open, writes value to the log pane or window. This is useful for debugging. See Appendix A for an example.stop log, start logSyntaxstop log start log
DescriptionIf the event log pane or window is open, disables and enables automatic logging of Apple events sent between applications; has no effect on thelogcommand.Only the old version of Script Editor (version 1.9), and Script Debugger, implementstop logandstart logproperly. If you try to use them in Smile or in the current Script Editor, you get a runtime error.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 19: Control
- InhaltsvorschauControl structures are the basis of a computer program's overall logic and "intelligence." They dictate the flow of a script. They are not commands; they are the signposts that describe how commands should be treated. They tell AppleScript how to decide what command should be executed next, or what to do if a command fails at runtime. They also modify how certain commands and operators are interpreted.When typing any block in this chapter, in the termination line just type the word
end. AppleScript fills in the missing term after compilation. (So, for example, don't typeend if; just typeend.) This shortcut saves time and is helpful for confirming that you have correctly structured your blocks.The "intelligent" behavior of a computer program depends upon its ability to make choices at runtime. These choices generally take the form of evaluating some expression and executing or not executing a particular block of code depending on how the evaluation turns out at that moment.One major form of choice is branching . We have a line or block of code that can be executed optionally. The computer evaluates a boolean expression, called a condition . If the condition is true, the line or block of code is executed; if it isn't, the line or block of code is skipped, and execution jumps to the line that follows it.In AppleScript, branching control is performed withif. An if block comes in several forms. The basic form is a single block of code that is executed only if a condition is true. If the condition is false, the block is skipped, and execution resumes after theend ifline.if condition then -- what to do if condition is true end if
It is also permitted to supply a second block withelse, to be executed if the condition is false. One or the other of the two blocks will be executed.if condition then -- what to do if condition is true else -- what to do if condition is false
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Branching
- InhaltsvorschauThe "intelligent" behavior of a computer program depends upon its ability to make choices at runtime. These choices generally take the form of evaluating some expression and executing or not executing a particular block of code depending on how the evaluation turns out at that moment.One major form of choice is branching . We have a line or block of code that can be executed optionally. The computer evaluates a boolean expression, called a condition . If the condition is true, the line or block of code is executed; if it isn't, the line or block of code is skipped, and execution jumps to the line that follows it.In AppleScript, branching control is performed with
if. An if block comes in several forms. The basic form is a single block of code that is executed only if a condition is true. If the condition is false, the block is skipped, and execution resumes after theend ifline.if condition then -- what to do if condition is true end if
It is also permitted to supply a second block withelse, to be executed if the condition is false. One or the other of the two blocks will be executed.if condition then -- what to do if condition is true else -- what to do if condition is false end if
Another syntax lets you specify multiple conditions. AppleScript will execute the first block whose condition is true, skipping the others. It is permitted to supply, withelse, a final block that will be executed if none of the conditions is true.if condition1 then -- what to do if condition1 is true else if condition2 then -- what to do if condition2 is true -- ... same for condition3, condition4, etc. [else] -- what to do if none of them is true end if
So, for example:set x to random number from 1 to 10 set guess to text returned of ¬ (display dialog "Pick a number from 1 to 10" default answer "") try set guess to guess as number on error return end try if guess < 1 or guess > 10 then display dialog "I said from 1 to 10!" else if guess < x then display dialog "Too small. I was thinking of " & x else if guess > x then display dialog "Too big. I was thinking of " & x else display dialog "Just right." end ifEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Looping
- InhaltsvorschauThe other major form of choice is looping , which involves branching back to the start of a block repeatedly. In AppleScript, looping is performed with
repeat. There are several varieties ofrepeat, but repeat blocks all take same basic form:repeat whatKindOfRepeat -- what to do end repeat
Loops involve repetition—perhaps a lot of repetition. Therefore, although I'm no great believer in worrying too much about optimization, if you're going to optimize your code anywhere, loops are the place to do it. A small increase in speed can add up tremendously over multiple repetitions. See Chapter 22.The big question with a repeat block is how you're going to get out of it. Obviously you don't want to repeat the repeat block forever , because that would be an infinite loop and would cause the computer to hang. Most kinds of repeat block include some instruction (as symbolized by whatKindOfRepeat in the syntax template), such as a condition to be evaluated, as a way of deciding whether to loop again.There are also some special commands for hustling things along by leaping completely out of the repeat block from inside it. These are the premature terminations of a repeat block. They can be used with any form of repeat block. Here they are:-
exit repeat -
This statement exits the innermost repeat block in which it occurs. Execution resumes after the
end repeatline. - try block
-
If the repeat block is inside a try block, throwing an error exits the repeat block by virtue of the fact that it exits the try block. See "Errors," later in this chapter.
-
return -
A
returnstatement exits the repeat block by virtue of the fact that it terminates execution of the handler or script.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Tell
- InhaltsvorschauA tell block , like an if block, comes in two forms: a genuine block and a single-line version. The block form is like this:
tell target -- code targeting this target end tell
The single-line version is like this:tell target to command
A tell block performs two distinct functions:-
It determines (at runtime) the target of the commands within the block.
-
It dictates (at compile time) the source that will be used for the resolution of the terminology that appears within the block.
The fact that a tell block does both these things makes a certain sense. After all, if you're going to be sending messages to the Finder, you're probably going to want to use the Finder's terminology. Nevertheless, the two functions are distinct, and it is possible to do either one without the other:-
To target an application without resolving any terminology, address it entirely by means of
of, without usingtell:get frontmost of application "Finder" -- falseThat works because the termfrontmostis defined by AppleScript itself, so there is no terminology to resolve; the Finder is targeted and a reply comes back. -
To resolve an application's terminology without targeting it, use a terms block (see the next section, "Using Terms From"):
using terms from application "Finder" set f to a reference to folder 1 end using terms fromThat works because the terms block uses the Finder's dictionary to resolve the termfolder; the Finder is not targeted (we're just forming a reference).
If the target in a tell block is an application, that application can be expressed as a variable rather than a literal application specifier. This variable may have as its value an application specifier, or it might be a reference to an object belonging to an application. Or, the target could be an application specifier, but the name of the application is a string variable instead of a literal string. In these situations, you'll probably have to use a terms block in order to get the code inside the tell block to compile.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Using Terms From
- InhaltsvorschauA terms block has the following structure:
using terms from application -- code containing terms to be resolved end using terms from
A terms block dictates which application's dictionary AppleScript should get the enclosed terminology from, without actually targeting that application. Terminology is resolved at compile time; therefore the application must be a literal application specifier (otherwise there's a compile-time error, "Can't make some data into the expected type"). A terms block is important only at compile time (and decompile time); it is effectively ignored at runtime.A question immediately arises of what happens when a tell block and a terms block are nested inside one another. The short answer is that the innermost block takes precedence. Here's an example of how to screw things up:tell application "Finder" using terms from application "Microsoft Entourage" get name of folder 1 -- error: Finder got an error: Can't get name of folder 1 end using terms from end tellThe problem there is that you're forcing AppleScript to resolvefolderby means of Entourage's dictionary. Entourage definesfolder, but using a different four-letter code from the Finder. You're still targeting the Finder, though, so when you do, you're talking to it in Entourage's language, which the Finder doesn't understand.But if an innermost tell block would not permit AppleScript to resolve terminology, a terms block surrounding it may do so. This will compile just fine:using terms from application "Finder" tell application someVariable get name of folder 1 end tell end using terms fromAnd it's completely equivalent to nesting the blocks the other way around:tell application someVariable using terms from application "Finder" get name of folder 1 end using terms from end tellThose examples illustrate how a terms block is typically used—it lets you target an application in a tell block without saying explicitly what application it is. Here, the application's name is expressed as a variable,Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - With
- InhaltsvorschauA with block is used to specify certain external attributes of Apple events sent to target applications from inside the block. Two types of with block are defined: a timeout block and a transaction block.Recall from "Apple Events" in Chapter 3 that during interapplication communications, the sender of an Apple event may attach to that Apple event a specification of how long it is willing to wait for a reply. This is the Apple event's timeout period. If the target does not reply within the specified timeout period, for whatever reason (the requested operation might be too lengthy, the target application might be otherwise engaged, and so forth), the system stops waiting for a reply and reports to the sender that the Apple event timed out. This report arrives as an error; your script can handle this error and proceed (see "Errors," later in this chapter).This entire mechanism is valuable, because (among other things) it rescues the sender from hanging indefinitely while waiting for the target to reply; if the target takes too long, the sender is able to proceed nonetheless. Of course, the sender must then do without any reply from the target, but a script can take account of this possibility. For example, reporting the problem to the user and proceeding, or even terminating in good order, is surely preferable to hanging or appearing to hang while waiting for a reply that is taking a long time to arrive and that may, indeed, never come.All Apple events sent to target applications have a default timeout value of one minute. This is a good compromise between waiting sufficiently long for lengthy operations to complete and waiting so long (or not having any timeout at all) that a script can hang or appear to hang. If this value is acceptable to you, you don't need a timeout block to change it.To change the timeout value temporarily using a timeout block , use this syntax:
with timeout of integer second[s] -- code affected by timeout value
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Considering/Ignoring
- InhaltsvorschauThere are two kinds of considering/ignoring block. One is the "ignoring application responses" block, which affects the nature of Apple events targeting an application. The other affects the details of string comparisons.Recall from "Apple Events" in Chapter 3 that during interapplication communications the sender of an Apple event may specify that it has no intention of waiting around for a reply. It doesn't care what the result is; it doesn't care if there's an error. It just wants to send the Apple event and be done with it, proceeding immediately to its own next step. In AppleScript, here's how to send such an Apple event:
ignoring application responses -- code end ignoringWithin the block, only Apple events sent to other applications are affected. Apple events sent to scripting additions, for example, are sent in the normal way and receive whatever replies they normally receive.For an example, see "Reduction" in Chapter 1. The code that opens a URL from the clipboard is wrapped in an "ignoring application responses" block, because I want the browser or mail client or whatever to open in the background and without my waiting for it; thus I can get on immediately with what I was doing.Inside an "ignoring application responses" block, it is possible to override the block by embedding a "considering application responses" block. You might use this construct, for example, to ignore responses from one application but not another.String considerations are optional switches that govern the nature of a string comparison (see "Comparison Operators" and "Containment Operators" in Chapter 15). For example, string comparison may be case-sensitive or case-insensitive. You can use a considering/ignoring block to govern this behavior.Until recently there was no mechanism for making string considerations visible to a targeted application. This meant that string considerations could operate only within AppleScript; a string comparison performed as part of a boolean test element specifier, for example, could not be affected by string considerations (see "Boolean Test" in Chapter 11 and "Who Performs an Operation" in Chapter 15). This limitation has changed, but applications must be rewritten if they are to notice and take account of string considerations (and I do not know of any application that has been rewritten in this way). See also "String and Clipboard" in Chapter 21 on theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Errors
- InhaltsvorschauAn error is a message at runtime saying, in effect, that something bad has happened and execution cannot continue. The sender of such a message is said to throw an error. The message percolates up through the chain of handler calls (the call chain ), looking for an error-handling block surrounding the line currently being executed; such a block is said to catch the error. If no such block catches the error, it percolates all the way up to AppleScript, and the script terminates prematurely (possibly with an error dialog ).This entire mechanism is extremely nice, because it provides a target application, or AppleScript itself, with a way to signal that it's impossible to proceed, interrupting the flow of code while leaving it up to the caller whether and how to recover. Your script can implement no error handling, in which case any runtime error will bring the script to a grinding halt. Or your script can implement error handling in certain areas where it expects an error might occur. It can recover from some errors and re-throw others, allowing them to terminate the script. It can even throw an error deliberately as a way of controlling the flow of code.An error can be a positive thing, and can be built into the structure of a command's implementation. For example,
display dialogthrows an error if the user clicks the Cancel button in the dialog. This need not kill your script. It will if you let it, and this can be a good thing (because Cancel often means "stop"). But alternatively, your script can catch the error as a way of learning that the user has cancelled, and can then proceed in some other appropriate manner.I'll talk first about how to throw an error, then about how to catch one.To throw an error, use theerrorcommand. It has five optional parameters:error [messageString] [number shortInteger] [partial result list] [from anything] [to class]
Here are the default values of the parameters:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Second-Level Evaluation
- InhaltsvorschauBy "second-level evaluation " I mean constructing and executing code at runtime. AppleScript has no built-in way of performing second-level evaluation. However, you can achieve much the same effect through the use of the
run scriptscripting addition command, which allows you to compile and run a string. (See "Compiled Script Files as Script Objects" in Chapter 8.)The use ofrun scriptis rather resource-expensive , because it requires that a completely new instance of the AppleScript scripting component be generated and torn down. It's also rather slow, because it takes time to compile the string. Finally, it's rather clunky, because a string run in this way has no communication with its surroundings; indeed, because a new instance of the AppleScript scripting component is generated, it has no surroundings at all. In other words, it isn't like a script object that can "see" globals at the point where it is defined and run.Nevertheless, there are things you can accomplish withrun scriptthat can be accomplished in no other way. For example, all terminology must be resolved at compile time, so the only way to construct completely dynamically, at runtime, a command involving terminology is by means ofrun script.In this example, we permit the user to enter part of an expression to be evaluated by saying it to the Finder:set d to "window 1" set p to "What Finder object would you like the name of?" set r to display dialog p default answer d set s to text returned of r set s to "tell app \"Finder\" to get name of " & s try set res to run script s display dialog res on error display dialog "Sorry, that didn't work." end tryFor another example ofrun scriptused for second-level evaluation, see "Record Properties" in Chapter 13.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 20: Dictionaries
- InhaltsvorschauIn Part II you learned the AppleScript language. It's essential to know this language if you're going to write AppleScript code; yet, ironically, the AppleScript language on its own won't get you very far. That's because AppleScript, all by itself, doesn't do very much; its real power and purpose lies in communicating with scriptable applications, which provide powers that AppleScript lacks. In order that you, the AppleScript programmer, may harness its powers, a scriptable application extends the vocabulary of the AppleScript language. For example, AppleScript can't make a new folder on your hard drive, but the Finder can; therefore the Finder extends AppleScript's vocabulary, supplementing it with terms such as
makeandfolderso that you can use AppleScript to command it (the Finder) to make a folder. This extended vocabulary is called a scriptable application's terminology . A dictionary is the means by which a scriptable application or scripting addition lets the world know how it extends AppleScript's vocabulary.A dictionary has two audiences—AppleScript and the AppleScript programmer. Let's consider how each of these audiences uses a dictionary:- AppleScript
-
AppleScript uses an application's dictionary at compile time to look up the terms that the programmer uses. In this way, AppleScript confirms that the terms really exist; as they don't exist within AppleScript itself, AppleScript cannot know without a dictionary that the programmer isn't just talking nonsense. At the same time, AppleScript uses the dictionary to resolve the terms into their corresponding Apple event form; otherwise, it wouldn't know what actual Apple event messages to send to the scriptable application at runtime. And it uses the dictionary when decompiling, to translate those Apple event terms back into English-like words for display to the programmer.
- The AppleScript programmer
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Resolution of Terminology
- InhaltsvorschauExample 20-1 exhibits some common patterns of terminology usage. With it, we'll model AppleScript's interaction with dictionaries during the process of compilation.Example 20-1. Simple terminology resolution
tell application "Finder" set c to display dialog ((count folders) as string) end tellCompilation of code like Example 20-1 proceeds in two distinct stages:-
The tell block causes AppleScript to locate a particular application and load its dictionary.
-
The terms inside the tell block are resolved.
Let's consider these stages one at a time.As AppleScript's compiler encounters a tell block (or a terms block) targeting a literal application, it attempts to locate this application and load its dictionary. If the compiler can't find the application, it will ask the user where it is; if the user cancels out of this process, refusing to choose an application, AppleScript will not compile the script (see "Missing External Referents" in Chapter 3).AppleScript will proceed happily at this point, provided that it can find the application, or the user chooses an application for it—any application. The compiler has not yet reached the stage of trying to resolve any actual terminology, so it doesn't matter whether there is any terminology to resolve, or even whether the application has a dictionary. All that matters so far is that the application referred to in code should be identified with some actual application.Loading a dictionary takes time, and may even require launching the application in question, which takes even more time. Once the current instance of the AppleScript scripting component has already loaded a particular application's dictionary, however, it doesn't need to do so again, because it now has a copy of the dictionary cached in memory. These are some of the reasons why a script typically takes longer to compile the first time.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Terminology Clash
- InhaltsvorschauThings don't always go smoothly when AppleScript resolves terminology. Terms are sought in the dictionaries of the innermost application, of AppleScript itself, and of all scripting additions, as well as in the script. Given such a large namespace comprising contributions from multiple independent entities, it is possible for conflicts to arise. Such a conflict is called a terminology clash . Either the programmer generates the clash by an unwise choice of variable names, or different dictionaries generate it by defining the same term in different ways.When the programmer causes a terminology clash, various things can happen. Sometimes the code won't compile; sometimes it won't run; sometimes it runs but gets an unexpected result; sometimes the clash is resolved sensibly and there's no problem.When the compiler stops you from using a term, the term is probably defined elsewhere as a different "part of speech" from how you're trying to use it.For example, this won't compile:
local count -- compile-time error: Expected variable name or property but found command nameThe termcountis defined by AppleScript itself as a command. Thus you're effectively trying to use a verb where a noun is expected.This won't compile:set sel to {length:2, offset:4} -- compile-time error: Expected variable name, class name or property but found command nameThis is similar to the previous example:offsetis defined as a command in a scripting addition. Observe thatlengthdoesn't cause a clash here, even though it's defined in AppleScript's own dictionary; that's because it's defined as a property, and you're using it as a property (see "Record Properties" in Chapter 13).This won't compile:local desktop -- compile-time error: -- Expected variable name or property but found application constant or consideration
Again, the problem is a scripting addition;desktopis a constant, part of an enumeration used in thepath tocommand. (See "Enumerations," later in this chapter.)Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Nonsensical Apple Events
- InhaltsvorschauAs we saw in a previous section ("Compile-time Error"), AppleScript will sometimes blow the whistle at compile time to indicate that you are using a term as the wrong "part of speech." This is extremely helpful. For example, you can't use a verb as a noun:
tell application "Finder" get name of eject -- compile-time error: Expected expression but found command name end tellAnd you can't assign to a class:tell application "Finder" set container to "howdy" -- compile-time error: Can't set «class ctnr» to "howdy". Access not allowed end tellYou have to supply valid parameter names:tell application "Finder" duplicate x by y -- compile-time error: Expected end of line but found "by" end tellTheduplicatecommand doesn't have abyparameter, and the compiler knows this.You can't make an element specifier out of something that isn't a class name:tell application "Finder" get name 1 -- compile-time error: Expected end of line but found number end tellThe compiler also displays some intelligence about singular and plural forms of a class name. The plural form of a class name is taken to be a synonym for theeveryelement specifier; otherwise, if you use a plural where a singular is expected or vice versa, the compiler will usually change it for you, silently:tell application "Finder" folder -- folder (the class name) folders -- {...}, a list of references to every folder folders 1 -- compiles as folder 1 folder 1 thru 2 -- compiles as folders 1 thru 2 end tellThis might lead you to believe that the AppleScript compiler will use an application's dictionary to confirm that what you're saying is valid. Don't believe that. It is all too easy to form a nonsensical expression and get it past the compiler—which will then form a nonsensical Apple event, which will be sent to the application at runtime. In general, you should not expect compilation to serve as a "sanity check."For example, the dictionary describes certain definite relationships between particular terms—this property is a property of this class, this element is an element of this class, this name is a class, this name is a property—but AppleScript largely ignores such information. As far as the compiler is concerned, property and element names areEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Raw Four-Letter Codes
- InhaltsvorschauWhen AppleScript compiles a script, it uses the dictionary to translate your English-like terminology into Apple events. When AppleScript decompiles a compiled script, it uses the dictionary to translate Apple events to English-like terminology.It is possible to do AppleScript's job for it and type a raw Apple event directly into a script. There is then no translation to be performed, and no dictionary is needed. Apple events, as we observed in Chapter 3, are constructed of four-letter codes. The notation is a keyword stating what "part of speech" this four-letter code is (such as
constant,property,classorevent), followed by a space, followed by the four letters (or, in the case of anevent, eight letters). The entire thing is wrapped in guillemets, also called chevrons («»). On the U.S. keyboard layout, these are typed using Option-\ and Shift-Option-\ (backslash).Using raw Apple events, we can target an application using its own terminology but without a tell block and without AppleScript's making any use of the application's dictionary. For example:get name of «class cdis» 1 of application "Finder" -- "feathers"The termnameis defined by AppleScript, but the termdiskis not. Yet we can use the termdiskoutside a tell block by entering it in its raw form.There are not many situations where this sort of thing is necessary, but it can be a useful strategy to know about. There are times when it can be a way of resolving a terminology conflict . Recall that earlier I mentioned a longstanding conflict between BBEdit and theoffsetscripting addition command. A similar problem exists when trying to use thepath toscripting addition command while targeting System Events (I owe this example to John Gruber):path to application support from user domain -- alias "feathers:Users:mattneub:Library:Application Support:" tell application "System Events" path to application support from user domain -- alias "feathers:Library:Application Support:" end tell
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Multiple-Word Terms
- InhaltsvorschauMany terms, especially commands in scripting additions, consist of multiple words . An example frequently used in this book is
display dialog. You might think that such a term would present extra challenges for resolution, but in actual fact just the opposite appears to be the case; multiple-word terms are a good thing:- You can't make one
-
Terms that you create in a script can't contain spaces unless surrounded by pipes—and pipes mean that no dictionary will be consulted. Therefore the probability of your creating a term in a script that clashes with a dictionary-based multiple-word term is zero.
- Clash is improbable
-
The more words a term consists of, the more likely it is that this term is unique among all dictionaries. This is especially important with scripting additions, whose terms are globally visible; for this reason, well-behaved scripting additions tend to use multiple-word commands.
- There is no clash with single-word terms
-
This is the really surprising part. Consider, for example, the scripting addition command
set the clipboard to. Even thoughset...tois a command, andtheis usually ignored, andclipboardcould be a variable name (and is in fact a property defined by AppleScript), no confusion arises:local clipboard, tester set clipboard to "Mannie" -- sets the variable clipboard set the tester to "Moe" -- sets the variable tester (ignoring "the") set the clipboard to "Jack" -- sets the system scrap
Though I don't know the details, a natural explanation of AppleScript's success in resolving multiple-word terms would be that it tries the longest possible combinations of words first.A multiple-word property name can be a little troublesome. The most commonly encountered example istext item delimitersEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - What's in a Dictionary
- InhaltsvorschauDictionaries are not presented to you as a verbal explanation with instructions for their use. They are structured in tabular form and typically displayed through a special dictionary viewer window within a script editor application. It takes time and practice to learn to use this dictionary viewer and to get the most out of its display . You need to be adept at reading and understanding a dictionary display if you are to communicate successfully with scriptable applications and scripting additions.The good news is that, starting in Tiger, the Script Editor 's dictionary display has been improved (for the first time since the dawn of AppleScript). Back in the bad old days, the dictionary was shown in a simple, primitive way (Figure 20-1). Its table of contents was a simple scrolling list down the left side, organized by "suites" that were not alphabetically arranged. Because you didn't know what "suite" a particular item was in, you had to scroll through the list looking for it in each suite. Clicking an entry in the list displayed its information in the main pane; that information was static and terse.In Tiger, the list on the left is an outline whose headings can be opened and closed; alternatively, you can use a columnar browser at the top of the window (Figure 20-2). A search field at the top lets you jump directly to a desired entry. The information for an entry is more copious: you learn not only what elements a class contains but also what classes it is an element of. And class names are hyperlinks, which you can click to jump to their entries and read their information.In Script Debugger , the dictionary display is even better. (See Figure 20-3; the screenshot has been doctored to shorten the window by omitting some of the elements.)The columnar browser at the top of Script Debugger's dictionary window has categories grouping commands and classes, letting you escape the tyranny of "suites." In the information displayed for an entry, the plural is given; properties and elements are shown in a clean, tabular layout; all datatypes (not just classes) are hyperlinked; and an extra section at the bottom of the display lists all classes of which this is anEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- The 'aeut ' Resource
- InhaltsvorschauWhen terminology is resolved, AppleScript itself is represented by a dictionary (see "Resolution of Terminology," earlier in this chapter). This fact comes as a surprise to many AppleScript users, because they don't think of AppleScript as having a dictionary. And no wonder, as they don't normally get to see this dictionary. Nevertheless, it is there. It's called the
'aeut'resource, and it lives in the AppleScript scripting component file, AppleScript.component (inside the package, it's at Contents/Resources/AppleScript.rsrc). It is loaded when the AppleScript scripting component comes into being, it looks basically like any other dictionary, and it defines the terminology for all of AppleScript's built-in commands and classes (except forgetandset, which are treated specially).If you'd like to get a look at the'aeut'resource, you can; both Smile and Script Debugger permit you to see it, by choosing File → Open Dictionary → AppleScript.The'aeut'resource contains the terms for virtually the entire AppleScript language, including comparison operators, prepositions, global script properties, and so forth. There are even some terms not discussed in this book (because in practice they don't arise, or may never even have been implemented, like theupper caseclass or theprint depthglobal property). You can learn a lot from perusing the'aeut'resource; at the very least, it can help to explain why certain variable names generate terminology conflicts (when the name is already defined in the'aeut'resource).Here's a quick guided tour of what you'll see if you decide to gaze directly upon the'aeut'resource (don't worry, it won't turn you to stone). The AppleScript Suite contains the global terms that make the AppleScript language work. The Type Names Suite contains many minor types without elements or properties, including secondary arithmetic classes such assmall integer(see Chapter 13) as well as thelocation referencetype so crucial to themakecommand (see "Relative" in Chapter 11); however, you might not see this in the display, because the Type Names Suite is normally suppressed from a dictionary display. (Applications take advantage of this to define terms needed for compilation but not suitable for human view.) The Standard Suite (also called the Core Suite) and the Text Suite are visible to the compiler but are usually overridden and extended by individual applications; not all the terms within them have any intrinsic implementation in AppleScript. So, for example, theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Inadequacies of the Dictionary
- InhaltsvorschauOne function of the dictionary is to show the human user how to speak AppleScript to a scriptable application in order to drive that application. But the very nature of a dictionary renders it insufficiently expressive to fulfill this function. A dictionary is merely a list of words. Words don't make a language. The problem, as Austin famously put it, is how to do things with words. That's what you want to know, but it's just what the dictionary is incapable of telling you. Dictionaries can be more discursive and explanatory thanks to the new sdef format, and it is to be hoped that developers will take advantage of this to improve them; but few dictionaries use this format, and even when they do, the fundamental problem will remain: a vocabulary list is not documentation.Here's an eclectic collection of some of the various ways in which the dictionary can fail the user. Forewarned is forearmed; I hope this discussion will make you a sharper reader of dictionaries and a wiser AppleScript programmer.This discussion is not meant to imply that all dictionaries are bad. On the contrary, some developers have worked hard to write careful, informative dictionaries. But it is hard work. You have to know AppleScript, you have to anticipate your users' needs and expectations, and you have to know the dictionary format and how to make the best of it. Most important, your application's scriptability has to have been well implemented to start with; for some useful guidelines from Apple, see
http://developer.apple.com/technotes/tn2002/tn2106.html.An application's object model is a hierarchy, essentially equivalent to the chain ofofs allowing you specify any of the application's objects (see "Properties and Elements," earlier in this chapter). Clearly this hierarchy requires a starting point; there must be some ultimate, top-level object in terms of which all others may be specified. In an Apple event, that top-level object isnull( ). But in AppleScript there is no way to express thisnull( )Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 21: Scripting Additions
- InhaltsvorschauA scripting addition (or osax) is a compiled code fragment, typically written in a language such as C, that extends the AppleScript language (see "Scripting Addition" in Chapter 3). A scripting addition has a dictionary, but it can't be targeted, and doesn't need to be; the commands that it implements are present as if built into AppleScript itself (see Chapter 20).A scripting addition can define events (commands), records (pseudo-classes), and coercions. Generally speaking, a scripting addition can fulfill two purposes:
- Add to AppleScript's powers
-
AppleScript is a "little language" (see Chapter 4), and in some ways it's just too little. A scripting addition can supplement AppleScript's powers by implementing additional commands.
- Define events
-
A scripting addition's dictionary can provide terminology for an event that some application might send to your script. Using this terminology, you can write an event handler to respond to the event. (See "Event Handlers" in Chapter 9.)
The default Tiger installation includes one scripting addition that adds to AppleScript's powers—the StandardAdditions osax. Many of the commands that it implements are so fundamental that this book treats them as part of the core language—for example,display dialog, which is used in examples throughout the book, and the very importantload scriptandstore scriptcommands (see Chapter 8). (The other installed scripting addition, Digital Hub Scripting, implements no functionality; it defines events, which are discussed in Chapter 26.)Writing a scripting addition is beyond the scope of this book. If you're interested, Appendix C lists some resources that may prove helpful.For some tips about speed when accessing a scripting addition command, see "Scripting Additions" in Chapter 22.A scripting addition implements functionality along with terminology for accessing it. So does a scriptable application. So why use a scripting addition rather than a scriptable application? There are clearly some things that scripting additions do better than scriptable applications. An application must be running in order to be targeted; if it isn't running, it must be found, which may require user intervention, and it must be launched, which takes time. But a scripting addition, once installed, is always present. If a scripting addition puts up some interface, that interface appears to be part of whatever application is being targeted at that moment. An application's dictionary has to be loaded (using a tell block or a terms block) in order for its terminology to be accessible; a script addition's terminology is simply part of the language. For this reason, a scriptable application can't be used to define the terminology for an event handler. And communicating with an application is slower than calling a scripting addition command (though less so than formerly).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Pros and Cons of Scripting Additions
- InhaltsvorschauA scripting addition implements functionality along with terminology for accessing it. So does a scriptable application. So why use a scripting addition rather than a scriptable application? There are clearly some things that scripting additions do better than scriptable applications. An application must be running in order to be targeted; if it isn't running, it must be found, which may require user intervention, and it must be launched, which takes time. But a scripting addition, once installed, is always present. If a scripting addition puts up some interface, that interface appears to be part of whatever application is being targeted at that moment. An application's dictionary has to be loaded (using a tell block or a terms block) in order for its terminology to be accessible; a script addition's terminology is simply part of the language. For this reason, a scriptable application can't be used to define the terminology for an event handler. And communicating with an application is slower than calling a scripting addition command (though less so than formerly).On the other hand, in some ways scripting additions are clearly a Bad Thing. There are some considerations of memory management, though these are too technical to describe here. A scripting addition is inconvenient, as in order to be available to a script, it must be not merely present on the user's machine (like a scriptable application) but installed in a particular location. Scripting additions can define coercions, but these cannot be documented in the dictionary. Finally, scripting additions invade the global AppleScript namespace, in ways that can be confusing and frustrating. A scripting addition may conflict with terminology the programmer would like to use; if a scripting addition was present when a script was compiled and absent when the script is run, the script may break, and the cause may be difficult to track down. (See Chapter 20 for examples and further discussion.)For these reasons and others, Apple actively discourages, by word and deed, the proliferation of scripting additions. The words include official statements such as the following: "There are severe limitations to what you can do in the context of a scripting addition, and the system costs of managing large numbers of scripting additions are high." (The main limitation Apple refers to here is that a scripting addition cannot define any classes. The Apple document I'm quoting also says that scripting additions can't maintain state between calls, but this is no longer true.)Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Classic Scripting Additions
- InhaltsvorschauThere is a difference between a scripting addition intended to be used with Mac OS 9 or before and a scripting addition intended to be used with Mac OS X. A Mac OS X-type osax will not work on Mac OS 9. A Mac OS 9-type osax will work on Mac OS X only if it has been Carbonized, meaning that internally its Toolbox calls have been linked against CarbonLib . In general, any particular osax file will probably be intended for one system or the other, not both. You may not be able to tell just by looking; if the Show Package Contents menu item appears in the Finder's contextual menu for an osax, it is certainly for Mac OS X, but otherwise you may need to consult the osax's documentation.Mac OS X on the one hand, and Classic running under Mac OS X on the other, implement AppleScript separately, but the two are compatible and Apple events travel back and forth between them. This raises the question of how the presence of Classic osaxen affects scripts running under Mac OS X. The answer seems to be that any osax terminology in code that targets a Classic application is handled by a Classic osax if possible. You can see this with a term like
display dialog, because the dialogs put up by the Mac OS X and Classic versions of this command differ in appearance. So, for example:set f to "gromit:Applications (Mac OS 9):SimpleText" tell application f to display dialog "hello" -- clearly the Classicdisplay dialogOn my computer, it is impossible to use English-like terminology to call a Classic scripting addition command from Mac OS X unless the same terminology is defined by an installed Mac OS X scripting addition. (The Apple documentation claims there's a way to do it with a terms block, but I have not gotten that to work.) So, for example, this works when run in the Classic Script Editor:min monitor depth -- 8But this won't even compile in the Mac OS X Script Editor:set f to "gromit:Applications (Mac OS 9):SimpleText" tell application f to get min monitor depth -- compile-time error: Expected end of line, etc. but found identifierEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Loading Scripting Additions
- InhaltsvorschauA scripting addition is not targeted; it is loaded. In particular, in order to be seen and used by a script, a scripting addition must be loaded by the AppleScript scripting component instance that is going to compile or run that script (see Chapter 3). For that to happen, the scripting addition file must be physically installed in any of a specific set of locations at the time that the AppleScript component instance is summoned into existence. On Mac OS X, those locations are, in the first instance, the three /Library/ScriptAdditions directories—in /System, at the top level, and in the user directory. (On previous systems, there was one location, the Scripting Additions folder; this was originally in the Extensions folder but was moved into the System Folder starting in Mac OS 8.)This architecture has historically caused headaches for script developers. If you wanted to write a script relying on a third-party scripting addition and distribute that script to others, you had to worry about how to guarantee that your end user had the right scripting addition in the right location by the time the script ran. Typically this involved social engineering. First you had to ascertain what scripting additions your script was calling. (Script Debugger is especially helpful here; it lists the scripting additions on which your script depends, even looking up any unresolved event codes on
http://macscripter.netfor you.) Then you had to distribute the required scripting additions with your script, or otherwise include instructions for acquiring them, along with loud and clear instructions on installing the scripting additions, in the hope of staving off complaints when your end user heedlessly tried to use the script without installing the scripting additions and got an error.Starting in Panther, an elegant solution to this longstanding difficulty was implemented at last: if you are willing to distribute your script as an application—either as an applet bundle or as an AppleScript Studio application—then if that bundle contains a directoryEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Standard Scripting Addition Commands
- InhaltsvorschauThe scripting addition commands present in a standard installation of Tiger (Mac OS X 10.4) are all implemented by the StandardAdditions scripting addition. You can consult the StandardAdditions dictionary to learn what commands it contains and to get the full details on their syntax, and it would be a waste of trees for me to repeat the information you'll find there. However, I'll list all the commands and provide some basic explanations and comments (and examples) that go beyond what the dictionary tells you. For most of these commands, where I or the dictionary might say "string," you should understand "or Unicode text," since StandardAdditions has been generally revised to be Unicode-savvy.(For
load script,store script, andrun script, see "Compiled Script Files as Script Objects" in Chapter 8. For thePOSIX fileclass, see "File and Alias" in Chapter 13 and "File Coercions" in Chapter 14. Fordo shell script, see Chapter 25. For digital hub scripting, folder actions, and CGI events, see Chapter 27.)These scripting addition commands put up dialogs, thus providing a modicum of user interaction. The dialog will appear in whatever application is being targeted at the moment, or in the host application if no application is being targeted. They should not be used in an environment where no user interaction is allowed (for example, in a Unixosascriptcommand). Recall (from "Errors" in Chapter 19) that the-128("User canceled") error thrown when the user clicks the Cancel button in one of these dialogs, if it percolates all the way up to AppleScript, does not normally result in an error dialog (though it will cause the script to terminate prematurely).display dialoggeneral informational, text entry, and button-choice dialoggeneral informational, text entry, and button-choice dialogA remarkably flexible little command. You can put up an information dialog. It can have an icon and a title. It can include a user text entry field; optionally, the user's text can appear as bullets (for password entry and so forth). You can dictate the names of up to three buttons, specify which is the OK button (which responds to Return) and which is the Cancel button (which responds to Esc or Command-Period, generates errorEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 22: Speed
- InhaltsvorschauThere are people who worry about squeezing every last possible ounce of speed out of AppleScript. They like nothing better than to sit down with a script and find clever ways of rearranging or reexpressing it so as to make it run faster. They have developed ingenious tricks and devices to optimize AppleScript code for speed. They even hold little contests to see whose script can complete a given task fastest! Personally, I'm not a great believer in optimizing code, but it's certainly true, as a practical matter, that most AppleScript programmers, sooner or later, do become concerned about speed. You've developed a script, and it's working, but when it runs it's taking longer than you think it should. You want to know whether there's anything you can do to make your script faster.A few general considerations will put speed into perspective:
- Things are better than they used to be
-
AppleScript is a lot faster than it once was, not just because we're all using vastly quicker computers these days, but because the runtime engine has been made more efficient. AppleScript used to be downright sluggish, and this was very noticeable back in the old days when computers had floppy disk slots and less than 4MB of RAM (and we all had to clean the streets with our tongues on the way to school). That's no longer the case.
- Interapplication communication is a bottleneck
-
AppleScript is all about communicating with other applications. It (AppleScript) isn't supposed to be fast, because it isn't supposed to be doing much of anything. It's supposed to be sending Apple events to scriptable applications, and as soon as it does that, speed is completely out of its hands; having handed an Apple event to the system to dispatch, AppleScript can do nothing but wait—and that's what most of a script's execution time probably consists of, waiting for some target application to receive an Apple event, do what it says to do, and return a reply.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Tools of the Trade
- InhaltsvorschauIn order to improve speed, you have to measure it. At the crudest level, you can do this with the
current datecommand, which captures the date-time at the moment it is issued, but this is good only to the nearest second. A better choice is the commandthe ticksfrom the Jon's Commands osax; this is particularly good for timing things, since a tick is about one-sixtieth of a second. Examples will appear later in this chapter.Script Debugger can also help you quantify speed. It doesn't yet provide true code profiling (reporting the time spent on different sections of your code), but it does report how long the script took to run and how much of that time was spent within AppleScript and how much was spent sending Apple events and how many Apple events were sent. It also provides code coverage, indicating what lines of your code were actually executed, so you don't waste effort optimizing areas of your script that aren't doing anything.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Apple Events
- InhaltsvorschauApple events are expensive, and some Apple events are very expensive. You can't do anything about the time spent waiting for each Apple event to execute, but perhaps you can minimize the number of Apple events sent. At the same time, you may be able to improve the efficiency of the particular Apple events you do send.The boolean expression at the top of a
repeat whileblock must be evaluated before every repetition of the block, and then once more in order to decide not to repeat the block any further. This means that it should not contain any commands whose result will not change during the repetition, as it would be needless and wasteful overhead to issue those commands each time through the loop.Here's a silly but telling example. Suppose we have two folders in the Finder, and we want to create enough new folders inside the first folder so that it contains the same number of items as the second folder. The following code expresses neatly and elegantly what we want done:set x to 1 tell application "Finder" set f1 to folder "f1" set f2 to folder "f2" repeat while ((count items of f1) < (count items of f2)) make new folder at f1 with properties {name:("f" & x)} set x to x + 1 end repeat end tellBut in the world of AppleScript, neat and elegant isn't always good. That code sends thecountmessage to the Finder twice for each time through the loop, when in fact we need only send it twice at the outset as we prepare for the loop:set x to 1 tell application "Finder" set f1 to folder "f1" set f2 to folder "f2" set c1 to count items of f1 set c2 to count items of f2 repeat while c1 < c2 make new folder at f1 with properties {name:("f" & x)} set x to x + 1 set c1 to c1 + 1 end repeat end tellObserve that the same issue would not arise if I had coded this usingrepeat with x from...to, because that construct evaluates everything once at the outset and then never again.Special considerations arise when usingrepeat with...inEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - List Access
- InhaltsvorschauWhen you access an attribute of a list, it is much faster to target a reference to the list, or the list as a script property, than to target the list directly. It's not entirely clear why this is; it seems like a bug. But it's a venerable and acknowledged bug, because even Apple's earliest documentation on AppleScript contains an example illustrating this point.In this code (based on Apple's example) we total the numbers in a long list:
set L to {} set total to 0 set bignum to 5000 repeat with i from 1 to bignum set end of L to i end repeat repeat with i from 1 to bignum set total to total + (item i of L) end repeat total -- 12502500, and it takes about 22 seconds to run on my machineThe big slowdown here is the second repeat block, accessing items of the list. If we access these items by way of a reference to the list, things speed up dramatically:set L to {} set refL to a reference to L set total to 0 set bignum to 5000 repeat with i from 1 to bignum set end of L to i end repeat repeat with i from 1 to bignum set total to total + (item i of refL) end repeat total -- 12502500, and it took less than a secondInstead of a reference, you can get the same extraordinary speed bump by referring to the list as a script property:set L to {} set total to 0 set bignum to 5000 repeat with i from 1 to bignum set end of L to i end repeat repeat with i from 1 to bignum set total to total + (item i of my L) end repeat total -- 12502500, and it took less than a secondThe magic word in that code ismy. Take it away, and the code takes 22 seconds to run; with it, the code runs in less than a second. (Discovery of this remarkable device is generally credited to Serge Belleudy-d'Espinose.)Now suppose all of that code is part of a handler, whereLis a local variable. You can't take a reference toL, so you'd have to use the trick of makingLa script property. To do so, you might have to create a script object expressly for this purpose; that may seem silly, but it's worth it:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Scripting Additions
- InhaltsvorschauOne of the main reasons for using scripting additions is speed. For repeated trigonometric calculations, for example, it is certainly going to be a lot faster to use a scripting addition, such as the Satimage osax, than to roll your own calculation (as disingenuously suggested at Apple's web site). Similarly, a scripting addition that implements transformations to a list, such as returning a list with a particular element deleted, is going to be faster than coding the same operation in AppleScript (see "LISP-likeness" in Chapter 4). Just how quickly a scripting addition is called, however, depends on how you call it.The osax architecture is such that a scripting addition appears to be present "inside" whatever application is being targeted when the scripting addition command is called. This behavior is noticeable, and useful, when a scripting addition puts up some user interface. For example, if the
display dialogcommand is called from within a tell block targeting the Finder, the dialog appears within the Finder; it's as if you'd given the Finder a new dialog.Behind the scenes, though, this architecture involves a serious inefficiency. The application itself is sent the Apple event denoting a scripting addition command. Obviously the application can't deal with this Apple event, so at that point the message is sent on up to the realm of scripting additions as a kind of fallback. This means that when you use a scripting addition command while targeting an application, that command must be routed through an extra step. This takes time, and in a context of repetition, the time adds up significantly.If, on the other hand, you use a scripting addition command outside of any tell block, or within a "tell me" block, the message is sent directly to the scripting addition, which is faster by about an order of magnitude—a very significant difference. Here's a script that demonstrates.set t to the ticks repeat 5000 times tell application "Finder" to get offset of "i" in "ticks" end repeat set t1 to (the ticks) - t set t to the ticks repeat 5000 times tell me to get offset of "i" in "ticks" end repeat set t2 to (the ticks) - t return {t1, t2} --Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Context
- InhaltsvorschauThe context or environment from which a script is executed can make a huge difference to its speed. This is in large measure because Apple events are expensive. In particular, what makes them expensive is the context switch involved in communicating between one application and another. Thus it is typically fastest, where possible, to run a script from within the application it targets. If an application has a Script menu, therefore, it is worth putting the script there and executing it from there to see if this makes it faster.(But also, there are some contexts that are inherently slower than others, for no discernable reason; it has something to do with how these contexts are programmed and that's that.)Here's a test script:
set x to (get current date) repeat 500 times tell application "iTunes" get name of it end tell end repeat set y to (get current date) set z to (y - x) tell application "Finder" activate display dialog z end tellTable 22-1 shows some rough timings on my machine for running that script from within various contexts.Table 22-1: Timings for the same script executed in different contexts ContextTimingiTunes's Script Menu0.15 secondRed Sweater FastScripts0.5 secondScript Debugger1.5 secondsApple's Script Menu8 secondsScript Editor9 secondsDragThingTimed out after 500 secondsEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 23: Scriptable Applications
- InhaltsvorschauAppleScript's chief purpose is to let you communicate with scriptable applications. How you target a scriptable application using AppleScript depends on whether the application is local (run on the same computer and by the same user as your script) or remote (run on a different machine, or on the same machine but by a different logged-in user). You might also like to know what scriptable applications are included with a default installation of Tiger. (On creation of scriptable applications using applets, AppleScript Studio, and Cocoa, see Chapter 27.)This book won't teach you how to script any particular application (see "The Scope of This Book" in the Preface). If the application comes with documentation or examples showing how to script it, start with that. For certain applications, there may be third-party books or web pages devoted to the topic of scripting it. The application will in any case have a dictionary (see Chapter 20).To target a scriptable application is to aim Apple events at it, like arrows. The principal linguistic device for targeting an application in AppleScript is the tell block containing an application specifier. Such a tell block actually has two purposes: it determines the target, if no other target is specified within the block, and (at compile time) it also causes a dictionary to be loaded, which may be used in the resolution of terminology. If the target of the tell block is expressed as a variable rather than a literal application specifier, no resolution of terminology is performed and the application is not sought for targeting until runtime when the code is actually encountered. Instead of a tell block, the
ofoperator (or its equivalents) can be used to form a target; this does not cause any resolution of terminology either. Terminology can be resolved independently of any tell block by means of a terms block.A reference to an object belonging to an application can also be used to target that application. The terminology within the reference has already been resolved (otherwise the reference could not have been formed in the first place); any further terminology accompanying the reference when you actually use it will have to be resolved independently.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Targeting Scriptable Applications
- InhaltsvorschauTo target a scriptable application is to aim Apple events at it, like arrows. The principal linguistic device for targeting an application in AppleScript is the tell block containing an application specifier. Such a tell block actually has two purposes: it determines the target, if no other target is specified within the block, and (at compile time) it also causes a dictionary to be loaded, which may be used in the resolution of terminology. If the target of the tell block is expressed as a variable rather than a literal application specifier, no resolution of terminology is performed and the application is not sought for targeting until runtime when the code is actually encountered. Instead of a tell block, the
ofoperator (or its equivalents) can be used to form a target; this does not cause any resolution of terminology either. Terminology can be resolved independently of any tell block by means of a terms block.A reference to an object belonging to an application can also be used to target that application. The terminology within the reference has already been resolved (otherwise the reference could not have been formed in the first place); any further terminology accompanying the reference when you actually use it will have to be resolved independently.(See "Missing External Referents" in Chapter 3; "Target" in Chapter 11; Chapter 12; "Application" in Chapter 13; "Tell" and "Using Terms From" in Chapter 19; and "Resolution of Terminology" in Chapter 20.)A local application is an application on the same computer and under the same user as the script. The specifier for a local application may consist of a full pathname string (colon-delimited) or simply the name of the application; the name should usually be sufficient.Specifying an application's name can be trickier than you might suppose. Back in the pre-Mac OS X days, typing the name of an application could be a maddening and tedious exercise. BBEdit's name wasn't"BBEdit"; it was"BBEdit 6.5". Excel's name wasEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Some Scriptable Applications
- InhaltsvorschauAs part of the default Tiger installation, Apple ships a number of applications with varying degrees of useful scriptability . Some of these are in places where you might think to look, but a number of them are not, so here's a quick survey of the scriptable applications you'll find on your computer. (Third-party applications, which are often the most important scriptable applications in a workflow, are not discussed here.)Of the applications in your /Applications directory, quite a number are usefully scriptable. iTunes is probably the most popular target; it is, perhaps, the only one of the iApps whose powers emerge to their fullest extent only in the presence of AppleScript. Address Book and iCal are essentially databases, and provide scriptable access to their data. Mail is scriptable, though there are many bugs and functionality holes.Safari , aside from control over its preferences and interface, responds to just one important command,
do JavaScript, but this command should not be underestimated, as it opens the door to some powerful capabilities. System Profiler is another one-trick pony: you can retrieve an XML version of its report, from which you can retrieve any desired information. Script Editor is scriptable enough to allow insertion of templated control structures through its contextual menu. If you see the Internet via modem or PPPoE, Internet Connect is a good way to query and manipulate your connection; you can connect and disconnect, and learn whether you are connected. iChat is scriptable enough to let you get buddy list information and send a message. TextEdit's scriptability is substandard. Other applications that are scriptable in a rudimentary way are Automator, DVD Player, Font Book, iPhoto, iSync, and QuickTime Player.The Finder, located in /System/Library/CoreServices, is the favorite target application for examples in this book—and with good reason. For all its faults, Finder scripting is a solid way to interact with the hierarchy of files and folders on your hard disk. It's very good at such things as renaming files, copying files, deleting files, creating folders and aliases, and describing the folder hierarchy. The Finder is also one scriptable application that is almost certain to be running (so that, for example, you have somewhere to start when targeting a remote machine).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 24: Unscriptable Applications
- InhaltsvorschauSome applications are not scriptable; they have no repertory of Apple events to which they are prepared to respond. The developers simply omitted this feature, like the tinsmith who forgot to give the Woodsman a heart. Other applications are scriptable, but not in the way you'd like; the thing you'd like to make the application do isn't among its scriptable behaviors. How can you script the unscriptable ? In theory, of course, you can't, and this book shouldn't be discussing this situation at all. AppleScript is about talking to applications with Apple events, and these applications are refusing to listen. It turns out, however, that in many cases you can use AppleScript in a different way, to direct simulated user actions at an unscriptable application. If you can do something with the mouse and keyboard, you may be able to automate those same mouse and keyboard movements using AppleScript, by means of a technology called GUI scripting .When you use GUI scripting, you are essentially driving a a macro program that functions as an intermediary between AppleScript and the target application. Such a program has the power to "see" an application's interface and to act as a kind of ghost user, pressing buttons, typing keys, and choosing menu items. Anything a user can do in an application can presumably be performed through some definable sequence of mouse and keyboard gestures; therefore it might be possible to emulate that sequence of gestures with a macro program. The result might not be as fast, elegant, or flexible as true scripting by means of Apple events, but might get the job done. The macro program used here will be System Events (see Chapter 23).Back in the pre-Mac OS X days, there were a number of very strong macro programs, such as QuicKeys , PreFab Player , and OneClick (see Appendix C for URLs). These depended upon a feature of the system architecture whereby third-party code fragments called system extensions (or INITs ) could be loaded into the system at startup in such a way as to modify the system's response to Toolbox calls. The code fragment would effectively interpose itself into the Toolbox call dispatch architecture, so that when the system was about to execute a certain piece of its functionality, this code fragment would be called instead; usually it would also call the system's original functionality, so as not to break the computer altogether, but along the way it would introduce functionality of its own. (On INITs, see Joe Zobkiw,Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Historical Perspective
- InhaltsvorschauBack in the pre-Mac OS X days, there were a number of very strong macro programs, such as QuicKeys , PreFab Player , and OneClick (see Appendix C for URLs). These depended upon a feature of the system architecture whereby third-party code fragments called system extensions (or INITs ) could be loaded into the system at startup in such a way as to modify the system's response to Toolbox calls. The code fragment would effectively interpose itself into the Toolbox call dispatch architecture, so that when the system was about to execute a certain piece of its functionality, this code fragment would be called instead; usually it would also call the system's original functionality, so as not to break the computer altogether, but along the way it would introduce functionality of its own. (On INITs, see Joe Zobkiw, A Fragment of Your Imagination [Addison-Wesley, 1995], Chapter 4.)The trouble with this approach was that INITs were a threat to stability and reliability. They caused no end of headaches for users, who often found that different INITs conflicted with one another, and for application developers, who would learn that their application misbehaved in the presence of some INIT. The ability of users to customize their own systems meant that every user's system could be essentially different from every other's.On Mac OS X, INITs are abolished. In fact, that's part of the point of Mac OS X: at bottom, every system should be a clean system, and all machines should reliably work the same way. But without INITs, there's no way for a third-party macro program to hook into the system's functionality at a level low enough for it to do the things that a macro program needs to do. This, in the early days of Mac OS X, made scripting the unscriptable next to impossible; and there was serious doubt as to whether there could ever be a macro program on Mac OS X.Then, however, a solution emerged from Apple itself. As part of an effort to make Mac OS X accessible to people who may not be able to use a mouse and keyboard or see a computer screen, Apple created the Accessibility API , a set of Toolbox commands that can do just what a macro program would do—"see" an application's interface and manipulate it like a ghost user wielding an invisible mouse and keyboard. Going even further, they made the Accessibility API itself scriptable via AppleScript, by way of System Events. When you do GUI scripting, you use AppleScript to send Apple events to System Events, which translates your commands into terms that the Accessibility API can understand.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Getting Started with Accessibility
- InhaltsvorschauThe prerequisite for GUI scripting to work is that the Accessibility API must be turned on. This may be done through the "Enable access for assistive devices" checkbox in the Universal Access system preferences. Unless this checkbox is checked, the scripts in this chapter will fail.Now examine System Events's dictionary; in particular, look at the Processes Suite. Here you'll find events such as
clickandkeystrokeand classes such asradio buttonandmenu item. The classes in question are allUI elementsubclasses. So your task is to use these events to operate on these classes, as a way of simulating clicks and keystrokes in the target application. The target application itself is expressed as anapplication processelement of System Events. Thus, AppleScript code that does GUI scripting will have a structure similar to the following:tell application "TextEdit" to activate tell application "System Events" tell application process "TextEdit" tell menu 1 of menu bar item "Format" of menu bar 1 click menu item 4 end tell end tell end tellIf you try that script, you'll see that it toggles the format of the frontmost TextEdit document between plain text and rich text (RTF). And you can see why: it literally chooses the fourth menu item of the Format menu. Observe that the target here is not TextEdit! It's System Events. The phrasetell application process "TextEdit"is not the same astell application "TextEdit"—it isn't an application specifier, it's merely an element specifier sent to System Events as part of the chain ofofs andtells specifying the complete target (see "The Chain of Ofs and Tells" in Chapter 11).The problem now, for any given task you'd like to perform by means of GUI scripting, is to express each desired interface element in terms of theUI elementobject model. This is not at all easy; ultimately, you must probably resign yourself to a certain amount of experimentation. There are, however, some utilities that can help you. These take advantage the fact that the Accessibility API can not only drive interface elements; it can also see them.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - GUI Scripting Examples
- InhaltsvorschauGUI scripting is something of an art, and needs either a big treatment providing the fruits of plentiful experience or a small treatment that shows a few useful examples and leaves you to explore further on your own. I've opted here for the latter; I'll just give a few practical examples of GUI scripting, without further elaboration.First I'll show how to toggle File Sharing on and off through the System Preferences application. System Preferences itself is not particularly scriptable; all you can really do is go to the desired preference pane. GUI scripting does the rest:
tell application "System Preferences" activate set current pane to pane "com.apple.preferences.sharing" end tell tell application "System Events" tell application process "System Preferences" tell tab group 1 of window "Sharing" click radio button "Services" select row 1 of table 1 of scroll area 1 click button 1 end tell end tell end tellNow let's work around the fact that TextEdit doesn't let you learn what text is selected. We can use GUI scripting to learn both what text is selected and where the selection is:tell application "TextEdit" to activate -- front window contains "this is a test of GUI scripting"; "test" is selected tell application "System Events" tell application process "TextEdit" tell window 1 tell text area 1 of scroll area 1 get value of attribute "AXSelectedText" -- "test" get value of attribute "AXSelectedTextRange" -- {11,14} end tell end tell end tell end tell
In this example, we work around the fact that you can't script TextEdit to close a window without saving it. The idea here is to close the window and allow the dialog to appear asking whether we want to save this document; when that happens, we press the Don't Save button using GUI scripting:tell application "TextEdit" activate close window 1 end tell tell application "System Events" tell application process "TextEdit" tell window 1 repeat while not (exists sheet 1) delay 0.5 end repeat click button "Don't Save" of sheet 1 end tell end tell end tellEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 25: Unix
- InhaltsvorschauOnce upon a time, Apple's Mac OS operating system and the Unix operating system were two completely separate worlds, each with its own idea of what constituted "scripting." On Mac OS, there was AppleScript and the OSA. On Unix, there was the command line, shell scripting, and the various shell scripting languages such as Perl. Now, with Mac OS X, those two worlds are united; both kinds of "scripting" are present, and there is communication between them, in both directions. Thus, you can combine the power of Unix scripting with the power of AppleScript.The way you call a Unix tool from AppleScript is with the
do shell scriptscripting addition command. The way you call from Unix into AppleScript is with theosascripttool. This chapter discusses both, along with some examples; you'll see how Perl,curl, and AppleScript can work together to perform a web query, and you'll see Ruby, AppleScript, and Microsoft Excel joining forces to perform textual analysis and graph the results.Your first step in getting acquainted with thedo shell scriptscripting addition command should be to read Apple's excellent technical note documenting it (http://developer.apple.com/technotes/tn2002/tn2065.html).The direct object ofdo shell scriptis a string representing the text you would type at the command-line prompt in the Terminal. Actually, that's not quite true, so do not imagine that you can blithely test a prospectivedo shell scriptcommand simply by typing it in the Terminal, as there might be some differences. Your Terminal shell is probablybashortcsh, whereas the shell fordo shell scriptissh(you probably won't experience this as a difference in Tiger, though, whereshisbash). Also, the default paths used bydo shell scriptmight not be the same as your own shell's paths, so to specify a command, you might have to provide a full pathname, such as/usr/bin/perlinstead of justperl. (That's not a real example, though, asEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Do Shell Script
- InhaltsvorschauYour first step in getting acquainted with the
do shell scriptscripting addition command should be to read Apple's excellent technical note documenting it (http://developer.apple.com/technotes/tn2002/tn2065.html).The direct object ofdo shell scriptis a string representing the text you would type at the command-line prompt in the Terminal. Actually, that's not quite true, so do not imagine that you can blithely test a prospectivedo shell scriptcommand simply by typing it in the Terminal, as there might be some differences. Your Terminal shell is probablybashortcsh, whereas the shell fordo shell scriptissh(you probably won't experience this as a difference in Tiger, though, whereshisbash). Also, the default paths used bydo shell scriptmight not be the same as your own shell's paths, so to specify a command, you might have to provide a full pathname, such as/usr/bin/perlinstead of justperl. (That's not a real example, though, asperlwill probably work just fine.)The result ofdo shell scriptis whatever is returned from the command via standard output (stdout). Unix newline characters are converted to Mac return characters by default, but you can prevent this if you wish. If the command terminates with a nonzero result (an error), an error by the same number is thrown in your script, and you can use this number (along with the man pages for the command) to learn what went wrong.For example, the following code requests a (decimal) number from the user and converts it to hex by means of the Unixprintfcommand:set theNum to text returned of (display dialog "Enter a number:" default answer "") set s to "printf %X " & theNum display dialog (do shell script s)
Thedo shell scriptcommand both accepts and returns Unicode text. But the actual medium of communication between AppleScript and the shell is UTF-8—that is, the direct object ofdo shell scriptis converted to UTF-8 before passing to the shell, and the reply from the shell is assumed to be UTF-8 and is converted to Unicode text (UTF-16) before arriving in your script. This is a sensible approach. Most Unix tools are probably unprepared to deal with Unicode input, and for characters in the ASCII range, the UTF-8 representation is the ASCII representation, so in effect the direct object is coerced automatically from Unicode text to a string, as long as it consists of just ASCII characters—which it usually will, so you usually won't have to worry about it. On the other hand, some Unix tools produce UTF-8 output, and it's nice to know that you can capture this seamlessly as the result; indeed, this can be a useful technique, as you saw in "Unicode Text" in Chapter 13.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Osascript
- InhaltsvorschauThree command-line tools are provided for accessing AppleScript from Unix—
osalang,osacompile, andosascript—of whichosascriptis the most important. So let's talk about the other two first.osalanglists the scripting components present on your machine (see "The Open Scripting Architecture" in Chapter 3):% osalang -l ascr appl cgxervdh AppleScript scpt appl cgxervdh Generic Scripting SystemIf you have other OSA components installed, they will also appear. (For example, if you use Script Debugger, you'll see AppleScript Debugger X and JavaScript.) The two four-letter codes identifying each component are used by OSA programmers, but typically won't arise in the context of your AppleScript experience. Then comes a series of flags describing the capabilities of this scripting component (see theosalangman page for their meanings). Finally, we have the name of the component. The "Generic Scripting System" is the general front end to the OSA (what Chapter 3 calls the generic system component or GSC); "AppleScript" is the AppleScript scripting component in particular. You can use either of these two terms as a language specifier in calling the other two command-line tools, but their effect will be identical, because the GSC will treat AppleScript as the default component. In general, unless you are using other OSA scripting components, you'll have no need forosalang.osacompiletakes as argument a text file, or some text provided on the command line, and generates a compiled script file or applet. For example:% cat > textfile.txt tell app "Finder" display dialog "Hello, world!" end ^D % osacompile -o compiledfile.scpt textfile.txt
The result is a compiled script file compiledfile.scpt that can be opened in Script Editor, executed by a script runner, and so forth. You can avoid the intermediate text file by including the script text as part of theosacompilecommand; the ensuing discussion ofosascriptshows how. The extension on the filename supplied in the-oparameter determines the type of file that's created; theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 26: Triggering Scripts Automatically
- InhaltsvorschauWhat causes a script to run? It might be that you deliberately run it—you press the Run button in a script editor application, for example, or you choose the script from the menu of a script runner environment. However, there is a whole class of situations where your script just sits there patiently and eventually some other process comes along and runs it, with no direct intervention or action on your part. I call this sort of milieu an automatic location (see Chapter 2). In an automatic location, AppleScript takes a passive instead of an active part. Instead of you personally setting a chain of events in motion, AppleScript operates in response to other events or activities taking place on your computer: someone inserts an audio CD, someone moves a file into a certain folder, a certain web page request appears at your server, a certain time of day arrives, the computer wakes from sleep, a certain hard drive is mounted, the telephone rings.There are a number of distinct automatic locations built into Tiger, and there are many varieties of circumstance in which third-party applications may trigger your scripts. A complete compendium of the ways in which scripts can be triggered automatically would be impossible, so the chief purpose of this chapter is to awaken you to the range of possibilities. You may be surprised by the sorts of role AppleScript can play on your computer.Preparing a script to operate in an automatic location is different from simply writing a script and running it. The reason is that you're not in charge. Some other process is—the process that will actually call your script—and you must know and obey the strictures imposed by that process. In general, you'll need to know two things:
- How to position your script
-
Some arrangement will have to be made so that the calling process knows where and when to find your script. The script may have to be in a particular folder. It may have to have a particular name. You may have to make some sort of preparatory arrangement, explicitly informing the process beforehand that when a certain thing happens, a certain script should be called.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Digital Hub Scripting
- InhaltsvorschauOn your computer, when you insert a music CD, likely as not, the application iTunes runs. But it doesn't have to be that way. This is one example of a general phenomenon called digital hub scripting: when a DVD, or a CD that doesn't consist of ordinary files, is inserted into your computer, the system can react by notifying a designated application. A little-known fact is that you can interpose your own code in this process; instead of iTunes, when an event like this occurs, a script of your choice is triggered, and can react in any desired manner.In the CDs & DVDs pane of System Preferences are the settings that determine how the system responds to a disk-insertion event. Here you can determine what application should be notified when the disk is inserted; alternatively, there's an option to run a script. The system will send one of five events to your script, and so your script will need to contain a handler for the appropriate event (see "Event Handlers" in Chapter 9). To learn what these events are, examine the dictionary of the Digital Hub Scripting scripting addition, where their terminology is defined.Let's say we want to take charge of what happens when an audio CD is inserted. This means that in our script there must be a
music CD appearedhandler. Suppose we call our script musicListener.scpt. In the CDs & DVDs preferences, we choose from the "When you insert a music CD" popup menu; the Run Script menu item lets us set musicListener.scpt to be called when a music CD is inserted. Here, we offer the user a choice of playing just one track of the audio CD:on music CD appeared d set diskName to d as alias as string set text item delimiters to ":" set diskName to text item 1 of diskName tell application "Finder" set L to name of every file of disk diskName end tell tell application "iTunes" activate set temp to {diskName, choose from list L} play file (temp as string) end tell end music CD appearedEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Folder Actions
- InhaltsvorschauA folder action involves a script being called automatically when certain events take place in a designated folder in the Finder. A script to be used as a folder action does not live in the folder with which it is associated; rather, it should live in your user library, at ~/Library/Scripts/Folder Action Scripts. Alternatively, such a script may live in the top-level /Library/Scripts/Folder Action Scripts, where you'll find some useful examples of folder action scripts, but the location in your user library is the default.Because the script and the folder are in different places, an extra step is required in order to form the explicit association between a particular script and a particular folder. In essence, this association is the folder action. To form such an association is to attach the script to the folder; to break the association is to remove the script from the folder. The script is not actually moved; attachment and removal are conceptual, not physical. Attachment and removal are implemented through the System Events application (see "System Events" in Chapter 23). System Events associates a folder with a script through a folder action object. These folder action objects are maintained as top-level elements of the System Events application class. System Events is then responsible for watching those folders to see whether an appropriate event takes place in the Finder, and, when it does, for sending the corresponding messages to any attached scripts. System Events doesn't do this, though, unless you also enable the folder actions mechanism as a whole—you do this through its
folder actions enabledproperty, which functions as a kind of master switch.It is necessary for the System Events application to be running in order for folder actions to work. Therefore, when you enable the folder actions mechanism, System Events is added to your Login Items. This is not a very robust approach, and it is easy to be puzzled when your folder actions stop working (because System Events is not running).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - CGI Application
- InhaltsvorschauA CGI application (for common gateway interface, if you must know) is a process that supplements a web server. When a request arrives for a page, instead of simply fetching a file on disk, the web server can turn to a CGI application and ask it for the page; the CGI application is expected to compose the entire HTML of the page, including headers, and hand it back to the web server, which sends it on as the reply to the client that made the request.Before Mac OS X, the communication between a web server and a CGI application was conventionally performed on Mac OS through Apple events. In particular, an Apple event usually known (for historical reasons) as the WebSTAR event is sent by the web server to the CGI application, describing the page request. The CGI application hands back the page as the reply to this Apple event (see
http://www.4d.com/products/wsdev/internetspecs.html). This means that an AppleScript applet could be used as a CGI application; such, indeed, was the traditional approach. Terminology for the WebSTAR event is defined in the StandardAdditions scripting addition; it is thehandle CGI requestevent. So in the past, you would write an applet implementing an event handler forhandle CGI request, and point your web server at that applet as the CGI application for certain web page requests.With the coming of Mac OS X, however, all this has changed. Of course if you're still using WebSTAR or some other web server that implements CGIs in the traditional Mac OS manner, you can continue using it directly with an applet. However, you are more likely to be using the web server that comes with Mac OS X, namely Apache, which doesn't work this way. Apache is a Unix web server, and Unix doesn't have Apple events. In Unix, environment variables, along with stdin and stdout, are used as the communication medium between the server and the CGI process.If you really want to, you can still use an AppleScript applet as a CGI application with Apache, but in order to do so, you need some intermediary application that swings both ways, as it were. On the one hand, this intermediary application must behave as an Apache-style CGI process, so that Apache has someone to talk to. On the other hand, this intermediary application must translate a CGI request from Apache into an Apple event and forward this Apple event to the appropriate applet; when the result comes back from the applet, it must then translate that result into the form Apache expects, and pass it back to Apache.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Timers, Hooks, Attachability, Observability
- InhaltsvorschauA number of applications will trigger your script in response to the arrival of a certain day or time. Your choice of such an application will depend upon your particular needs (and possibly what you're willing to spend). Possibilities to examine include Script Timer , iDo Script Scheduler , and various
cronfront ends. There is also QuicKeys X, though this is rather pricey for what it does. Another option might even be iCal (which is already present on your computer); the alarm for an event or to-do item can involve running a script.A hook is a point in an application's operation where it is willing to turn to you—or more exactly, to a script you've supplied—to ask what to do. Many sorts of application use a hook to let you customize their behavior at key moments. Such, for the most part, are the applications listed in "Automatic Location" in Chapter 2. Thus, one example is iCal: as I mentioned a moment ago, when an alarm fires, iCal can run a script in response. Similarly, Apple's Mail program and Microsoft Entourage let you create rules that are performed in response to the arrival of mail messages meeting certain criteria; one of the things a rule can do is to run a script.Some applications have hooks as their life blood, so to speak. An example is Salling Clicker , which is all about responding to a handheld device (such as a Bluetooth phone) by running a script. Another example is Ovolab Phlink , which answers the phone and turns at every stage of the phone call to your scripts to see what to do—when the phone rings, when it answers, when the caller presses keys on a touchtone phone, when the call ends, and so forth.Phlink calls into your script by taking advantage of named parameters. For example, when a phone call arrives on your computer, if you have a script called ring in the proper location, it will be called. In order for this to work, your script must contain a handler with this definition:on incoming_call given call:theCall, ¬ callername:theName, ¬ callerid:theId, ¬ ringcount:theCount --Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 27: Writing Applications
- InhaltsvorschauYou might wish to create a standalone application, perhaps as a way of distributing your script to other users in a form that's easy to use. AppleScript provides the simplest way in the world to write an application: just save your script as an applet . An applet is a true standalone application; it can even accept drag-and-drop of files and folders onto its icon, and (most surprising) it's scriptable. However, an applet has essentially no interface (except for
display dialogand other user-interactive scripting addition commands). You can wrap your script in a full-fledged interface, with windows, buttons, text fields, menus, and similar bells and whistles, using AppleScript Studio, a free development environment that lets you create a Cocoa application even if the only programming language you know is AppleScript. Another use of AppleScript Studio is to wrap your script in the smaller interface of an Automator action; users can then customize it through its interface and link it to other actions to create their own workflows. This chapter also deals with some more advanced issues related to writing applications: how to get started adding scriptability to a Cocoa application, and how an AppleScript Studio application can communicate internally from Cocoa to AppleScript. (See also "Application" in Chapter 2.)An applet is a compiled script wrapped up in a simple standalone application shell (see "Applet and Droplet" in Chapter 3). To make a script into an applet, save it from a script editor application as an application instead of as a compiled script. You select this option in the Save As dialog. When you launch the resulting application (by double-clicking it in the Finder, for example), the script runs.It is also possible to save a script as an application bundle. From the outside, this looks and works like an applet. Because it's a bundle, though, you can do things with it that you can't do with an old-style applet, such as storing extra resources inside it; for an example, see "Persistence," later in this chapter. Also, an application bundle can call scripting additions contained within itself; see "Loading Scripting Additions" in Chapter 21. Keep in mind that this format is not compatible with systems earlier than Panther.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Applets
- InhaltsvorschauAn applet is a compiled script wrapped up in a simple standalone application shell (see "Applet and Droplet" in Chapter 3). To make a script into an applet, save it from a script editor application as an application instead of as a compiled script. You select this option in the Save As dialog. When you launch the resulting application (by double-clicking it in the Finder, for example), the script runs.It is also possible to save a script as an application bundle. From the outside, this looks and works like an applet. Because it's a bundle, though, you can do things with it that you can't do with an old-style applet, such as storing extra resources inside it; for an example, see "Persistence," later in this chapter. Also, an application bundle can call scripting additions contained within itself; see "Loading Scripting Additions" in Chapter 21. Keep in mind that this format is not compatible with systems earlier than Panther.For applet formats, and for special applet behaviors when an application is missing as an applet starts up, see "Applet and Droplet" and "Application Missing When an Applet Launches" in Chapter 3, and "Using Terms From" in Chapter 19. Persistence works in applets; see "Persistence of Top-Level Entities" in Chapter 8. For the behavior of an applet when a runtime error occurs, see "Errors" in Chapter 19. When an applet runs, no decompilation takes place; for one way this can affect the behavior of your script, see "Raw Four-Letter Codes" in Chapter 20.When you elect to save a script as an applet, you are given some options that affect how the applet will behave:
- Stay Open
-
The normal behavior of an applet when started up is to run its script and then automatically quit . A stay-open applet does not automatically quit; it just sits there running, like any application. An applet has some built-in menus , and in a stay-open applet the user has time to access them; they include a Quit menu item, which the user can choose to quit the applet. If stay-open applet has already run its script, what's the point of its staying open? For the answer, see "Applet Event Handlers," later in this section.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - AppleScript Studio
- InhaltsvorschauAppleScript Studio is a free development environment from Apple allowing you to write Cocoa applications using the AppleScript language. It would require an entire book to discuss AppleScript Studio adequately, so in this section I'll just explain what AppleScript Studio is and how it works, and talk about how you might go about learning it more fully; I'll also provide a simple hands-on example of AppleScript Studio in action.AppleScript Studio is Cocoa . The precise sense in which I mean this will be clearer in a moment, but it's a simple truth on the face of it, and it means that to understand what AppleScript Studio is, you need to know what Cocoa is.Cocoa is a massive application framework included as part of Mac OS X. This framework knows how to do all the things that an application might typically wish to do. For example, it can put up windows, in which it can display many different kinds of interface elements for interacting with the user, such as buttons and text fields and sliders and tables and so forth. It also provides very strong text and graphics capabilities. Cocoa is a remarkably well-constructed application framework, striking an excellent balance between power and flexibility; with Cocoa, it's easy to write a simple standard application quite quickly, while at the same time the framework usually provides enough leeway so that the programmer can fully customize the application's behavior if desired. The presence of Cocoa as part of Mac OS X makes it much easier for programmers to write sophisticated, powerful, Mac OS X-native applications, while at the same time such applications often require relatively little code, because so much of the code that does the work resides in the framework.AppleScript Studio is Apple's way of letting you, the AppleScript programmer, take advantage of the Cocoa application framework without having to learn a different programming language. The "native" Cocoa programming language is Objective-C , and to use Cocoa fully, you would want to learn that language. But as an AppleScript programmer, you might already have written a working script. You don't want to rewrite its functionality in some other language; you want to enhance your script with a more sophisticated user interface than AppleScript alone can provide. AppleScript Studio can let you do this. Think of it as a way to leverage an existing script into a Cocoa application, a way to wrap a Cocoa interface around AppleScript functionality with relative ease.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Cocoa Scripting
- InhaltsvorschauAdding scriptability to an application that you write has been, in the past, not a task for the faint of heart. An
'aete'-format dictionary is difficult to create and maintain. On the programming side, the system needs to be able to call into your application when an Apple event arrives, so as your application starts up it must register the appropriate functions with the Apple Event Manager, and when an Apple event arrives, your code must parse it (no mean feat, especially if it involves a reference to an object in your application) and respond appropriately.For this reason, programmers have often relied on sample code and application frameworks for assistance in making an application scriptable. There was some concern among programmers, therefore, when Mac OS X first emerged, over how it would be possible to take advantage of the Cocoa application framework and make an application scriptable at the same time. Since those early days, support for scriptability has gradually been folded into Cocoa; this is called Cocoa scripting . Cocoa scripting is still not perfect, but at least it has passed its infancy, and in Tiger it is easier than ever, thanks in part to the introduction of the sdef-based dictionary.Thus, if you're a Cocoa programmer, Cocoa scripting in Tiger is a good way to start adding scriptability to your application. Getting started is the hardest part, though, for several reasons:- Multiple workplaces
-
You have to coordinate the sdef dictionary with your code. If you make a mistake in either of them, or if you cause one of them not to match the other, some aspect of scriptability can fail mysteriously.
- Scattered documentation
-
The documentation is copious, but it's scattered in many different places, and elementary tasks and common problems are often not explained clearly. Also, Cocoa scripting uses "key-value coding," which means that often there is no way to look up a troublesome method in the documentation (because it
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - AppleScript Studio Scriptability
- InhaltsvorschauIt is natural to wonder whether an AppleScript Studio application is scriptable. The news here is something of a mixed bag.AppleScript programmers who are accustomed to writing applets, which are inherently scriptable, will be disappointed to learn that AppleScript Studio applications are not scriptable in quite the same easy way. The mere presence of a top-level entity in an applet's script makes the applet scriptable with respect to that entity, but no such thing is true of an AppleScript Studio application. So, for example, you cannot simply tell our SearchTidBITS application to
displayResults( )(see Example 27-7). The problem is that an AppleScript Studio application is not merely an application shell wrapped around a script; it's a true Cocoa application. So your message isn't magically routed to the correct script, because in the way stands the entire mechanism of a Cocoa application.On the other hand, an AppleScript Studio application is scriptable with respect to the entire AppleScriptKit.sdef dictionary, which is actually visible to users though a script editor application as if it were your application's own dictionary. This means that whatever built-in commands you can give from within the code of an AppleScript Studio application, a user can give from outside it. For example:tell application "SearchTidBITS" activate tell window "search" tell matrix 1 set content of cell 1 to "AppleScript" set content of cell 3 to "Matt Neuburg" end tell tell button 1 to perform action end tell end tellThat's exactly the same as if the user had typed values into two of the text fields and then pressed the Search button! Initially this may sound exciting, but most AppleScript Studio programmers ultimately regret that things work this way, for the following reasons:- It's messy.
-
The user who looks at your AppleScript Studio application's dictionary sees the entire confusing AppleScriptKit.sdef dictionary, which says nothing as to your application's purpose or what the user can appropriately do when scripting it.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix A: The AppleScript Experience
- InhaltsvorschauThis appendix illustrates informally the process of developing AppleScript code. The idea is to convey to the beginner some sense of what it's like to work with AppleScript, and 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. 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 appendix, 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 whatsoever 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 we'll extract some general principles on how to approach a task with AppleScript.
Section A.1: The Problem
Section A.2: A Day in the Life
Section A.3: Conclusions, Lessons, and Advice
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The Problem
- InhaltsvorschauI 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 department 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 A-1 presents the example the illustration department provides.
Table A-1: How the O'Reilly illustration department wants figure files named Fig. No.FilenameCaption (or description)1-1wfi_0101.epsOverview of the Windows NT operating system environment.1-2wfi_0102.epsName space presented by the Object Manager.1-3wfi_0103.epsFilter drivers in the driver hierarchy.2-1wfi_0201.epsLocal File System.2-2Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - A Day in the Life
- InhaltsvorschauAlthough 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, where I examine the terminology I can use in speaking to this application 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 A-1.This is a massive document and, to the untrained eye (or even to the trained eye), largely incomprehensible. 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 study its classes. 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 when working with FrameMaker through its graphical user interface, to add an illustration to a FrameMaker document, using the template my publisher has set up, I begin by inserting a table, and then, to make the reference to an illustration file, I choose the Import File menu item. Sure enough, there is a
tableclass in the FrameMaker dictionary, but it is not at all clear to me what kind of entity I generate by choosing Import File.At this point an idea strikes me. Perhaps I should start with an existing illustration and see if I can find a way to ask FrameMaker, "Hey, what's this?" In fact, very near the start of FrameMaker's dictionary—and you can see this in Figure A-1—there's a listing calledEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Conclusions, Lessons, and Advice
- InhaltsvorschauYou'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 (commands). 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, andcount; evenselectis fairly standard. The only unusual verb I ended up using wasfind. I spent almost all of the time worrying about the nouns. The biggest problem in AppleScript is referring to the thing you want to talk about, in the manner that your scriptable application expects and accepts.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix B: Apple Events Without AppleScript
- InhaltsvorschauConsidering AppleScript purely as a vehicle for constructing and sending Apple events to scriptable applications (and for receiving and parsing the replies), and in light of the shortcomings and inconveniences of the AppleScript language, one may reasonably wonder why it might not be possible to construct and send Apple events using some other (possibly more attractive) language. Such an approach would have the advantage of letting you work in a language or a development environment you favor, plus at runtime you'd bypass the overhead of the AppleScript compiler and runtime engine. As a matter of fact, there are several such alternative languages to choose from. It is not at all trivial to mold another language to operate on Apple events in a way that parallels AppleScript's own approach, especially because AppleScript does some odd (or buggy) things under the hood, and also because of the inherent problem of extensible terminology; nevertheless, it can be and has been done. This is not, strictly speaking, an AppleScript matter; indeed, it is quite clearly an anti-AppleScript matter! So in theory, discussion of it should have no place in this book. Nevertheless, my own favorite ways of sending Apple events have often included some non-AppleScript language or other, and the subject is certainly an interesting one, so I've included some information on the topic here, as an appendix.Here, then, are some ways to send Apple events without using AppleScript. Your choice might depend upon what languages you like or are already using, and upon the nature of a particular language's implementation of Apple events. Throughout this appendix, the "model events" (the Apple events we will attempt to construct and send for purposes of example) will be those corresponding to the following script:
tell application "BBEdit" make new document tell document 1 set its text to "Hello, world!" end tell end tellAt programming level, these events provide a nice balance between simplicity and complexity: we're forming a two-level object specifier, which is a fairly interesting thing, without getting too deep into the nitty-gritty. At the user level, the result is pleasantly satisfying, as (if our code is correct) we can see the new window appear in BBEdit with the words "Hello, world!" proudly emblazoned on it.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Pure Raw Apple Events
- InhaltsvorschauIf you're a Carbon programmer, you can construct a raw Apple event yourself, directly, in code. A number of other languages, such as Objective-C/Cocoa and REALbasic , give you the wherewithal to do the same thing in a possibly more convenient form. Still, no matter how you slice it, building a raw Apple event is a lot of work, and because every Apple event is different, this approach is not particularly general or flexible. You can compensate by developing libraries of wrapper functions, and Apple provides such libraries (such as the MoreAppleEvents sample code available at the developer web site), but it's still a fairly unpleasant procedure.Here's some code for generating and sending our model events in Objective-C/Cocoa. Actually it's blended with C/Carbon, because Objective-C, curiously, although it provides some fairly convenient ways to construct the pieces of an Apple event, provides no way to send the event once it's been constructed. Also it's a lot more convenient to construct an object specifier in Carbon than in pure Cocoa. For simplicity, issue of memory management and error checking are ignored:
[[NSWorkspace sharedWorkspace] launchApplication:@"BBEdit"]; NSAppleEventDescriptor* bbedit = [NSAppleEventDescriptor descriptorWithDescriptorType:typeApplicationBundleID data:[@"com.barebones.bbedit" dataUsingEncoding:NSUTF8StringEncoding]]; NSAppleEventDescriptor* ae = [NSAppleEventDescriptor appleEventWithEventClass:'core' eventID:'crel' targetDescriptor:bbedit returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID]; [ae setParamDescriptor:[NSAppleEventDescriptor descriptorWithTypeCode:'docu'] forKeyword:'kocl']; AESendMessage([ae aeDesc], NULL, kAENoReply | kAENeverInteract, kAEDefaultTimeout); ae = [NSAppleEventDescriptor appleEventWithEventClass:'core' eventID:'setd' targetDescriptor:bbedit returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID]; [ae setParamDescriptor: [NSAppleEventDescriptor descriptorWithString:@"Hello, world!"] forKeyword:'data']; AEDesc docu1; CreateObjSpecifier('docu', [[NSAppleEventDescriptor nullDescriptor] aeDesc], formAbsolutePosition, [[NSAppleEventDescriptor descriptorWithInt32:1] aeDesc], YES, &docu1); AEDesc allText; CreateObjSpecifier('ctxt', &docu1, formAbsolutePosition, [[NSAppleEventDescriptor descriptorWithDescriptorType: 'abso' bytes:"all " length:4] aeDesc], YES, &allText); NSAppleEventDescriptor* allTextDesc = [[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&allText]; [ae setParamDescriptor:allTextDesc forKeyword:keyDirectObject]; AESendMessage([ae aeDesc], NULL, kAENoReply | kAENeverInteract, kAEDefaultTimeout);Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - JavaScript
- InhaltsvorschauThe free JavaScript OSA component file from Late Night Software (see "Other Scripting Languages" in Chapter 3) implements an OSA language that appears in your script editor application; this language is JavaScript with some additions that allow it to construct and send (and receive) Apple events.Actually, JavaScript OSA can construct Apple events in two ways. If you like, you can construct raw Apple events by a process quite similar to the earlier REALbasic example. However, JavaScript OSA can also read the dictionary of the target application in real time and incorporate its terminology into the JavaScript language. The target application is, in effect, represented by an object with properties and methods corresponding to AppleScript attributes and commands. Here is code to generate and send our model events:
with (MacOS.appBySignature("R*ch")) { make(_types.document); document[1].valueOf( ).text = "Hello, world!"; }This mode of expression is extraordinarily compact and direct. Awithclause and dot notation replace the chain ofofs andtells; true assignment with an equal-sign replacesset. Elements appear as arrays. Certain distinctions that are muddied by AppleScript are clarified; the termdocumentis different as an element and as a class, for instance.JavaScript OSA can't express every kind of Apple event (in particular, boolean test specifiers are not supported), but this is compensated for by the powerful combination of the cool and elegant object-oriented JavaScript language with the automatic implementation of AppleScript terminology. Most important, JavaScript OSA is an OSA language, meaning that it's usable just about anywhere you would use an AppleScript compiled script file. For instance, many of the scripts I use with script runners such as Entourage's and BBEdit's Script menus are written in JavaScript.To learn more about JavaScript OSA, download it and look through the "Introducing JavaScript OSA" manual (written by yours truly).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - UserTalk
- InhaltsvorschauUserTalk is the native scripting language of UserLand Frontier and its inexpensive "little brother," Radio UserLand. Frontier is now also once again available in a free version, which is open source.UserTalk does not read an application's dictionary in real time, the way JavaScript OSA does. In UserTalk, all terminology (not only as relates to Apple events, but the entire language) is implemented through a hierarchical namespace table called "the database." Every name in the database corresponds to a value; a value can be a string, an integer, a raw four-character code, a script written in the UserTalk language, a subtable, or any of a dozen other types of value. The namespace is navigated through dot notation, starting at the top level, which is called
root. Certain nodes in the database are short-circuited, though, so that an unqualified term is sought at these points directly. English-like AppleScript terminology is implemented through the database, like everything else; to drive an application, you need a table to translate from English-like terms to four-letter codes, scripts, and so forth. This is called the glue table for that application. Construction of a glue table must be performed separately before you can start targeting a given application. The process of constructing a glue table is largely automatic (Frontier includes a script that can read an application's dictionary and generate the corresponding table), but too involved to describe here. Let's just assume, therefore, that we have previously constructed a BBEdit glue table. Then the code to generate our model events is as follows:if !(bbedit.isRunning( )) launch.application(bbedit.appinfo.path) with objectmodel, bbedit make(document) set(document[1].text,"Hello, world!")The termbbeditrefers to our glue table (located in thesystem.verbs.appstable, one of the short-circuited areas of the database). The termobjectmodelrefers to a table insystem.macintosh(another short-circuited area) where certain common terms are defined. Thewithclause means: "Look for these terms starting inEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Perl
- InhaltsvorschauPerl has a surprisingly long history on the Macintosh; years before it was present as part of Unix in Mac OS X, it had been ported to the Classic Mac OS by Matthias Neeracher (see
http://www.ptf.com/macperl). Modules to form and send Apple events were naturally part of this port (seehttp://www.ptf.com/macperl/depts/articles/IPCwMP.html). Support for these modules has continued, under the guidance of Chris Nandor, and they are available to Mac OS X users.Once again, you have a choice: you can form the raw Apple events yourself, using Mac::AppleEvents, or you can use AppleScript terminology through Mac::Glue. The operation of Mac::Glue is similar to Frontier with its glue tables (and is probably deliberately modelled after it); a glue table for a given application must be formed and stored on disk before you can target that application using AppleScript English-like terminology. In order to get started, you will need Mac::Carbon (which includes Mac::AppleEvents) as well as Mac::Glue; on Tiger these are installed by default, but it can't hurt to check for more recent versions.To make glue, run thegluemacUnix tool. For example:% sudo /usr/bin/gluemac /Volumes/gromit/Users/matt2/extra/BBEdit\ 8/BBEdit.app Making glue for '/Volumes/gromit/Users/matt2/extra/BBEdit 8/BBEdit.app' What is the glue name? [BBEdit]: Created and installed App glue for 'BBEdit.app, v8.2.3' (BBEdit)The resulting glue table contains a document in the standard Perl documentation format (POD, for "plain old documentation") expressing the dictionary in Perl syntax. You can read it withperldoc; another tool,gluedoc, provides a shortcut to the desired document:% gluedoc BBEditUsing the POD document and the instructions for Mac::Glue, you can usually figure out the Perl analogue to an AppleScript expression. Here's code to generate our model events:use Mac::Glue; my $bb = Mac::Glue->new('BBEdit'); $bb->launch( ); $bb->make(new => 'document'); my $doc = $bb->obj(document => 1); my $text = $bb->obj(property => 'text', $doc); $bb->set($text, to => 'Hello, world!');Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Python
- InhaltsvorschauHamish Sanderson's Appscript brings AppleScript terminology to Python. It comes with a standard installer package; double-click and run the installer and you're good to go. Scripts must be run using
pythonw, not plainpython. Here's the code for generating our model events:from appscript import * bb = app('BBEdit') bb.make(new=k.document) bb.documents[1].text.set('Hello, world!')No glue is necessary; like JavaScript OSA, Appscript reads the dictionary and constitutes an appropriate application object behind the scenes. It does this very quickly, and it's even faster if you run the supplied background application AppscriptTerminologyServer. The Python code is structured in a compact, intuitive, highly legible manner, incorporating all the best features of UserTalk and JavaScript; this is partly due to Python itself and partly due to Appscript's clean and thoughtful implementation. Appscript is also easy to learn. An included tool,htmldoc.py, generates an HTML-formatted display of an application's dictionary with the Python version of its terminology. (Alternatively, you can use the HTMLDictionary standalone application, included with the installer, which does the same thing.) And a particularly nice extra is an interactivehelpcommand for exploring either the terminology or the live attributes of an application's objects. So, for example, within the interactivepythonwinterpreter:>>> bb.documents[1].help('-s') ================================================================================ Appscript Help (-s) Reference: app(u'/Volumes/gromit/Users/matt2/extra/BBEdit 8/BBEdit.app').documents[1] -------------------------------------------------------------------------------- Current state of referenced object(s) --- Get reference --- app(u'/Volumes/gromit/Users/matt2/extra/BBEdit 8/BBEdit.app').text_documents.first ---- Properties ---- properties: {k.contents: u'Hello, world!', k.ID_: 7038242, k.file: k.MissingValue, k.modifiable: True, k.state_modified: False, k.name: u'untitled text 3', k.modification_date: datetime.datetime(2005, 9, 22, 12, 51, 51), k.source_language: '', k.FTP_info: k.MissingValue, k.line_breaks: k.Unix, k.container: None, k.text: u'Hello, world!', ...Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix C: Tools and Resources
- InhaltsvorschauThis appendix provides sources for software, tools, documentation, and further information on various topics discussed in this book.Free software from Apple mentioned in this book is already on your hard drive. For AppleScript Studio (Xcode , Interface Builder ) you must install the developer tools. Applications mentioned by name only, but not discussed or used in examples, are not listed here.
Section C.1: Scripting Software and Tools
Section C.2: Scriptable Software
Section C.3: AppleScript Documentation
Section C.4: Writing a Scripting Addition
Section C.5: Writing a Scriptable Application
Section C.6: Portals, Instruction, and Repositories
Section C.7: Mailing Lists
Section C.8: Books
Section C.9: Unix Scripting
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Scripting Software and Tools
- Inhaltsvorschau
-
Script Debugger, a commercial environment for developing and debugging scripts and exploring scriptable applications, crucial to my use of AppleScript (this book couldn't have been written without it):
http://www.latenightsw.com
-
JavaScript OSA , an Apple-event savvy OSA language version of JavaScript:
http://www.latenightsw.com/freeware/JavaScriptOSA/
-
Mac::Carbon and Mac::Glue, modules for using Apple events in Perl:
http://projects.pudge.net
-
Appscript, an Apple events implementation for Python:
http://freespace.virgin.net/hamish.sanderson/appscript.html
-
UserLand Frontier , and its inexpensive little brother Radio UserLand , a brilliant, powerful scripting environment with its own scripting language and built-in persistent storage, great interapplication communications, and Internet server/client capability. There is now also a free open source version:
http://www.userland.com
http://sourceforge.net/projects/frontierkernel
-
OSABridge , a set of components making Perl, Ruby, Python, PHP, sh, and Tcl available as OSA languages:
http://homepage.mac.com/philip_aker/
-
Loader , a system for rationalizing AppleScript libraries:
http://applemods.sourceforge.net
-
PreFab UI Browser , an indispensable tool for GUI scripting:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Scriptable Software
- Inhaltsvorschau
-
BBEdit , a scriptable text editor:
http://www.barebones.com/products/bbedit/
-
MultiAd Creator , an extraordinarily scriptable and attachable page layout and drawing program:
http://www.creatorsoftware.com/products/
-
Mailsmith , a scriptable email client:
http://www.barebones.com/products/mailsmith/
-
Eudora , a scriptable email client:
http://www.eudora.com/email/
-
Microsoft Entourage , Word , and Excel —a scriptable email client and an incredibly scriptable word processor and spreadsheet program:
http://www.microsoft.com/macoffice/
-
FileMaker Pro , a scriptable database program:
http://www.filemaker.com
-
GraphicConverter , a scriptable image processing program:
http://www.lemkesoft.com/en/graphcon.htm
-
Tex-Edit Plus , a scriptable styled text editor:
http://www.tex-edit.com
-
NoteTaker , a scriptable outliner:
http://www.aquaminds.com
-
StuffIt Expander , a scriptable file expander/decoder:
http://www.stuffit.com/mac/
-
SpamSieve , a scriptable program that filters spam, communicating with email client programs through AppleScript:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- AppleScript Documentation
- Inhaltsvorschau
-
The main AppleScript page, including a number of example scripts and other resources:
http://www.apple.com/applescript/
-
AppleScript on Mac OS X from the developer's point of view:
http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptX/
-
The AppleScript Language Guide—still the primary official documentation, and an important source of information, even though it often obfuscates more than it explains and is valid only to Version 1.3.7:
http://developer.apple.com/documentation/AppleScript/Conceptual/AppleScriptLangGuide/
-
Incremental release notes and change notes postdating the Language Guide:
-
AppleScript 1.4 change notes:
http://developer.apple.com/technotes/tn/tn1176.html#applescript -
AppleScript 1.4.3 change notes:
http://docs.info.apple.com/article.html?artnum=75073 -
AppleScript 1.5.5 change notes:
http://developer.apple.com/technotes/tn/tn2010.html#applescript -
AppleScript 1.6 change notes:
http://docs.info.apple.com/article.html?artnum=60835 -
AppleScript 1.7-1.9.2 release notes (at this point Apple seems at last to have recognized the importance of gathering and linking to the release notes from a single location):
http://www.apple.com/applescript/release_notes/
-
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Writing a Scripting Addition
- Inhaltsvorschau
-
Apple's tech note on how to write a scripting addition:
http://developer.apple.com/technotes/tn/tn1164.html
-
A seminal article from MacTech Magazine:
http://www.mactech.com/articles/mactech/Vol.10/10.01/ExtendApplescript/
-
Useful notes from an experienced scripting addition coder:
http://www.latenightsw.com/technotes/ScriptingAddition/
-
Sample code for creating a scripting addition:
http://www.satimage.fr/software/en/downloads_sample_projects.html
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Writing a Scriptable Application
- Inhaltsvorschau
-
Making a Cocoa application scriptable:
http://developer.apple.com/documentation/Cocoa/Conceptual/Scriptability/
-
Sdef-based scriptability:
http://developer.apple.com/documentation/Cocoa/Conceptual/ScriptableCocoaApplications
-
Apple's scripting interface guidelines:
http://developer.apple.com/technotes/tn2002/tn2106.html
-
Apple's sample scriptability code:
http://developer.apple.com/samplecode/Sketch-112/Sketch-112.html
-
Sdef Editor , a brilliant and absolutely crucial free utility by Jean-Daniel Dupas:
http://chezjd.free.fr/Creation/logiciel.php?sign=SdEd
-
Andrew Stone's tutorial:
http://www.stone.com/The_Cocoa_Files/Adding_Applescript.html
-
Dustin Voss's tutorial:
http://cocoadev.com/?HowToSupportAppleScript
-
Don Briggs's examples and tools:
http://homepage.mac.com/donbriggs/
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Portals, Instruction, and Repositories
- InhaltsvorschauIt's better to list a few web sites that between them contain virtually all important links than to try to list all those links, so here they are.
-
ScriptWeb, a web portal to all things scripting-related:
http://www.scriptweb.org
-
MacScripter, a live collection of news items, examples, and links; now also incorporates AppleScriptCentral:
http://macscripter.net
-
MacScripter's scripting additions repository:
http://osaxen.com
-
Bill Cheeseman's encyclopedic site of history, examples, instruction, links, and more:
http://www.applescriptsourcebook.com/home.html
-
Main portal for XML-RPC and SOAP servers:
http://www.xmethods.net
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Mailing Lists
- InhaltsvorschauMailing lists remain an important source of assistance, and are often haunted by Apple employees and by users of wisdom and experience.
-
Apple's AppleScript list:
http://lists.apple.com/mailman/listinfo/applescript-users
-
Dartmouth's venerable MacScrpt list (in whose name the "i" is not only silent, it's downright absent):
http://www.lsoft.com/scripts/wl.exe?SL1=MACSCRPT&H=LISTSERV.DARTMOUTH.EDU
-
Apple's list for developers writing scriptable applications:
http://lists.apple.com/mailman/listinfo/applescript-implementors
-
Apple's AppleScript Studio list:
http://lists.apple.com/mailman/listinfo/applescript-studio
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Books
- Inhaltsvorschau
-
Danny Goodman's groundbreaking AppleScript Handbook:
http://www.dannyg.com/pubs/index.html
-
Ethan Wilde, AppleScript for the Internet: Visual QuickStart Guide (Peachpit Press, 1998):
http://www.amazon.com/exec/obidos/ASIN/0201353598/
-
Ethan Wilde, AppleScript for Applications: Visual QuickStart Guide (Peachpit Press, 2001):
http://www.amazon.com/exec/obidos/ASIN/0201716135
-
Shirley Hopkins, AppleScripting InDesign (Dtp Connection, 2000):
http://www.amazon.com/exec/obidos/ASIN/0970726511/
-
Shirley Hopkins, AppleScripting QuarkXPress (Dtp Connection, 2000):
http://www.amazon.com/exec/obidos/ASIN/0970726503/
-
Ethan Wilde, Adobe Illustrator Scripting with Visual Basic and AppleScript (Adobe, 2002):
http://www.amazon.com/exec/obidos/ASIN/0321112512/
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
- Unix Scripting
- Inhaltsvorschau
-
Dave Taylor, Learning Unix for Mac OS X Tiger (O'Reilly Media, 2005):
http://www.oreilly.com/catalog/ltigerunix/
-
Larry Wall et al., Programming Perl, Third Edition (O'Reilly Media, 2000):
http://www.oreilly.com/catalog/pperl3/
-
Mark Lutz, Programming Python, Second Edition (O'Reilly Media, 2001):
http://www.oreilly.com/catalog/python2/
-
"Programming Ruby," an excellent online book:
http://www.rubycentral.com/book/
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. -
Zurück zu AppleScript: The Definitive Guide
