Getting Started with Handlers (Part 1 of 3)

Welcome AppleScript developers! Some of you may be familiar with my regular AppleScript columns in X-Ray Magazine and MacTech Magazine. I am pleased to announce that, in addition to my columns in those fine publications, I will be writing regular AppleScript columns, presently on a monthly basis, for MacScripter. Be sure to check back on a weekly basis, though, for excellent AppleScript-related columns by many other great authors!

I have chosen to begin my column here at MacScripter by providing an introduction to handlers, a topic that will end up spanning three articles (part 2, part 3). My reason for choosing this topic is that shortly, I plan to start focusing on AppleScript Studio. Since AppleScript Studio development requires heavy use of handlers, and since every AppleScript developer should be making use of handlers on a regular basis anyway, it only seems fitting to begin with this topic. Let’s get started.

Handler Overview

Before walking through the creation and usage of handlers, I would like to first discuss the definition of a handler. A handler is a set of AppleScript statements, which are grouped together, and associated with a single command. When this command is triggered, or called, the statements within the handler will be executed.

Some handlers are actually defined by applications, scripting additions, or by the system. These types of handlers are known as command handlers. A Folder Action is an example of a command handler.

You can also define your own custom handlers as you write your scripts. These types of handlers are known as subroutine handlers.

Subroutine Handler Benefits

We will discuss command handlers in detail at a later time. For now, I would like to discuss some of the benefits of creating custom subroutine handlers of your own. As I have already stated, every AppleScript developer should be making use of subroutine handlers whenever possible. As you will see, by doing so, you can actually begin to automate your own AppleScript code development.

When writing scripts, you will often find yourself in situations where you need to write the same code over and over again. For example, you might be writing a script that uses the Finder to create folders in various locations on the hard drive. Repetitive situations such as this are ideal times to make use of subroutine handlers.

A subroutine handler, which may consist of multiple lines of AppleScript code, can be called over and over throughout a script by issuing a single command. Think about this concept for a moment. Rather than writing those same multiple lines of code over and over again throughout your script, you can write them once, and then trigger them at any time with one command. Talk about automation!

In order to get the most use out of handlers, when you write them, you should try to make them as modular and opened as possible. This will allow you to trigger your handlers in a wide range of situations. It will also enable you to extract your handlers from your current script, and potentially utilize them in other scripts again in the future. In fact, many AppleScript developers even construct extensive libraries of their handlers, which they can access whenever they need to perform various tasks. This is good practice when scripting. Why should you need to write the same code twice, when you can write it once as a modular handler that can be used over and over again in the future?

Another benefit, especially in complex scripts, is that handlers can actually make a script easier to navigate and troubleshoot, should problems occur during execution. Rather than scanning through a lengthy script searching for a problematic area, you can navigate directly to the handler in which the problem is occurring. You will then have a much smaller chunk of code to troubleshoot. In some cases, you may even be able to extract the handler all together and test it in isolation, in order to try to reproduce the problem.

Creating a Subroutine Handler Definition

Now that we have discussed the concept of a subroutine handler, let’s discuss how you would go about creating one. The first thing that you will need to do is determine what code you want to execute when the handler is called. As in my earlier example, suppose you want to create a folder somewhere on the hard drive…


tell application "Finder"
	make new folder at desktop with properties {name:"Folder 1"}
end tell

To convert the code above to a subroutine handler, you would begin by creating what is known as a handler definition. A handler definition will always begin with the word on or to, followed by a name for the handler and any parameters for the handler.

Whether you choose to use the word on or to to begin your handler definition is up to you. Personally, I prefer the word on. A handler name must adhere to the same rules that apply when assigning a variable name. Namely, it may contain only letters, numbers, and underscores, it must begin with a letter or an underscore, and it may not be a reserved word.

Next, a handler definition will contain any AppleScript statements to be executed when the handler is called. Finally, a handler definition ends with the word end, followed by the handler name again. Using the previous example code, we could construct the following handler definition:


on makeFolder()
	tell application "Finder"
		make new folder at desktop with properties {name:"Folder 1", label index: 1}
	end tell
end makeFolder

Executing a Subroutine Handler

In a handler definition, the handler name serves as the command by which you can execute the code within the handler. For example, the handler above may be called from anywhere within my script by issuing the following command.


makeFolder()

When executed, this handler will create a folder named “Folder 1” in the user’s desktop folder. When calling a handler, you must specify values for any of that handler’s parameters. In the handler above, we have not yet defined any parameters, hence the empty parentheses.

Handler Parameters

A handler, just like any command, may have parameters. These parameters may be used to pass information to the handler, to be processed by the statements within the handler. For example, in the handler above, rather than hard coding the output location and folder name, we might want to allow this information to be passed to the handler. This would make the handler more modular, allowing it to be triggered in a wider variety of situations.

In a handler, parameters may be defined in one of two ways, as positional parameters, or as labeled parameters. The method you choose to use when defining a subroutine handler’s parameters is up to you. I prefer positional parameters, as I find them much less confusing and flexible. However, we will discuss both methods.

Positional Parameters

Positional parameters are contained within parentheses that follow the handler name, and are separated by commas. Like a handler name itself, parameters must adhere to the same naming rules as variables. The following example code defines two parameters in our handler.


on makeFolder(theOutputFolder, theNewFolderName)
	tell application "Finder"
		make new folder at theOutputFolder with properties {name:theNewFolderName}
	end tell
end makeFolder

As the example code above demonstrates, these parameters may be referenced by the statements within the handler in the same manner that a variable would be referenced. The parameters will receive their values when the handler is called.

When triggering a handler with positional parameters, the handler call must specify values for all of the handler’s parameters, in the order in which they are defined in the handler’s definition. For example, to trigger the handler above, the following call could be made, which would create a folder named “Folder 2” on the user’s desktop.


makeFolder(path to desktop folder, "Folder 2")

Labeled Parameters

Labeled parameters also follow the handler’s name, but are not contained within parentheses, or separated by commas. Rather, they are preceded by one of a number of predefined labels.
When assigning labeled parameters, the following predefined labels may be used for any indirect parameters:

about, above, against, apart from, around, aside from, at, below, beneath, beside, between, by, for, from, instead of, into, on, onto, out of, since, through, thru, and under

A handler definition with labeled parameters may also have a direct parameter, which must be preceded by the label of, and must immediately follow the handler name.

The following example builds upon our previous handler, but utilizes labeled parameters, rather than positional parameters. This particular handler will create a folder within a specified folder using the name provided, and then assign a label color to the newly created folder. This handler defines both a direct parameter, as well as two indirect parameters.


on makeFolder of theNewFolderName at theOutputFolder above theLabelColor
	tell application "Finder"
		make new folder at theOutputFolder with properties {name:theNewFolderName}
		set label index of result to theLabelColor
	end tell
end makeFolder	

To execute this handler, the handler name is used, followed by values for any parameters, preceded by their corresponding labels. For example, triggering the handler with the following call would create a folder named “Folder 3” on the desktop, and then set its label color to orange.


makeFolder of "Folder 3" at (path to desktop) above 1

Like in a handler definition itself, when calling a handler with labeled parameters, if a direct parameter is specified, it must immediately follow the handler name, as demonstrated above. Indirect parameters, on the other hand, because they are associated with specific labels, may be placed in any order desired. For example, the following handler call would achieve the exact same result as the previous one.


makeFolder of "Folder 3" above 1 at (path to desktop)

In Conclusion

Hopefully, some of this business about handlers will encourage you to begin exploring them further on your own. As I have mentioned several times already, subroutine handlers can be very beneficial when writing your scripts. Of course, we have only really scratched the surface here. We have yet to discuss the scope of variables within handlers, command handlers, and return values. We will continue this discussion in my next column.

Until next time: just script it!

Link to part 2: http://www.macscripter.net/viewtopic.php?id=24738