Find a Library, Fast

Find a Library, Fast

“Script libraries” are collections of frequently-used AppleScript subroutine handlers that you compile and save somewhere on your hard drive. By keeping these handlers in a library, you conserve disk space and the trouble of retyping them into every client script that uses them. A client script simply loads the library and calls one of its handlers. Suppose you’ve saved a library named “My Favorite Handlers.scpt” on your desktop, and one of the handlers in the library is named “performMyHandler” and takes a single parameter. The client script would call the handler like this:


set myLibPath to (path to desktop as string) & "My Favorite Handlers.scpt"
set myLib to (load script file myLibPath)

tell myLib to performMyHandler(myParameter)

But the desktop is a nutty place to store a script library. I had wondered for years what is the “right” folder in which to store script libraries, but I’ve become convinced that there isn’t any right folder. By the time Mac OS 9 came out, there were many good candidates, including the Scripts folder, the Scripting Additions folder, and the Application Support folder. With Mac OS X, you also have to consider whether to use the local domain (for all users of your computer) or the user domain (for the curren user only). No doubt every scripter will have a different opinion.

If you distribute your script library and client scripts to others, it would be nice to let them store the script library in any of the likely places. So now the question is, How do you tell a client script to find which of the usual suspects contains a needed library? Asking the user to locate it every time the client script is run would be a drag. You could use nested repeat loops to match every file in every possible folder and subfolder against the name of the library, but that is likely to be quite slow. A faster method would make it possible for a script to locate a library without a noticeable delay and without bothering the user to find it, no matter where a particular user thinks script libraries belong.

Here’s a little handler I put together to search in the usual places, without using the Finder. It’s surprisingly fast, because it doesn’t use AppleScript to match all the possible files. Instead, it takes advantage of the fact that asking for the file in a particular folder instantly generates an error if the file isn’t there. The handler looks only in folders for which AppleScript provides a constant, the so-called “special” folders.

First, I’ll show you the classic Mac OS version:


to search for itemName at specialFolders
   repeat with aFolder in specialFolders
      try
         return alias ((path to aFolder as string) & itemName) as string
      on error number -43 --item not there, go to next folder
      end try
   end repeat
   return "" --nothing found, return empty string
end search

Here’s how to use the search handler to find the Standard Additions scripting addition (as if you didn’t already know where it is):


set usualPlaces to {scripts folder, scripting additions, application support}
seearch for "Standard Additions" at usualPlaces

The reason this little script is so fast is that the repeat loop only cycles through three or four folders, not through all the files in those folders. For each folder, the script takes the simple shortcut of asking the Standard Additions scripting addition to return the Path To the desired file or folder. The scripting addition is built with fast code, and it makes short work of returning an error if the target isn’t in the folder. It also, of course, quickly supplies the actual path to the file if it is in the folder. There’s no need for the script to repeat-loop its way through all those targets.

The Mac OS X version of the script is only a little different. The main complication is that it has to try all four of the standard domains, which requires an inner repeat loop to go through each of them for each target folder. Also, instead of testing for error number -43, it doesn’t specify an error number. This is because some of the special folders in some of the domains require special permissions, and you might get a different error number if you don’t have them.

Here’s the Mac OS X version of the script, including both the handler and the main body of the script:


set usualPlaces to {scripts folder, scripting additions, application support}
search for "StandardAdditions.osax" at usualPlaces

to search for itemName at specialFolders
   repeat with aFolder in specialFolders
      repeat with aDomain in {system domain, local domain, user domain, network domain}
         try
            return alias ((path to aFolder from aDomain as string without folder creation) & itemName)
         end try
      end repeat
   end repeat
   return ""
end search

These scripts don’t search nested folders. It would be very useful to do so, because the Scripts folder is usually full of subfolders and your target might be in any of them. The challenge is to do it without using any but Apple’s scripting additions. This is left as an exercise for the reader.