Tuesday, February 16, 2010

Importing external scripts in same directory in Applescript

I started dabbling in Applescript the other day and rather quickly ran into an annoying limitation. Applescript has a mechanism for loading external scripts, but it requires absolute paths. I like keeping my code portable, and that means absolute paths aren't allowed. After some experimenting and digging around online I finally managed to find a solution.

Load as Property

The suggestion I was building off of was to load the script as a property. I'm still not sure exactly what "property" here actually entails, but here's the initial suggestion:

property _ScreenSize : load script (alias "pathtoscript")

_ScreenSize's doStuff()

This works as long as the path I give it is absolute and a literal string. If I try storing the path in a variable and setting it like this:

set _path to "Macintosh HD:Users:herms:code:applescript:scpt:screen_size.scpt"

property _ScreenSize : load script (alias _path)

then I get the following error when I try to save:


From my testing it appears that loading a property happens at compile time, not run time, so you can't use variables to store/manipulate the path. So this won't work.

Load as Variable

On a hunch I tried changing the code to just set the library as a variable instead of using the property stuff. Surprisingly (at least to me, maybe not to someone who's familiar with Applescript) this worked. I could have the path in a variable and load whatever that pointed to:

set _path to "Macintosh HD:Users:herms:code:applescript:scpt:screen_size.scpt"

set _ScreenSize to load script (alias _path)

Building the Path

The only thing remaining was to build the path. A number of places online suggested using path to me to get the path to the current script, but I ran into trouble trying to modify that path. I could get it as either a file object or a string, but I couldn't figure out any way to actually modify either of those. The only string operations I've found so far are concatenation and checking the contents of a string. I couldn't find documentation on how to actually modify strings.

I did find a forum post somewhere (sadly I've lost the link) that showed how to have Finder do the work for you. It's probably not optimal performance-wise, but it works and the code is rather short:

tell application "Finder"
  set _myPath to container of (path to me) as text
end tell

That sets the _myPath variable to the string containing the HFS-formatted path to the directory containing the script. Just add ":scriptname" to the end and you have the path for what you want to load.

Loading the Script

I ended up creating a load_script method that takes the name of the script file to load and returns the loaded script:

on load_script(_scriptName)
  tell application "Finder"
    set _myPath to container of (path to me) as text
  end tell

  load script (alias (_myPath & _scriptName))
end load_script

To use it I do:

set _ScreenSize to load_script("screen_size.scpt")

and here's an example of using a handler defined in the script:

set {_x, _y, _width, _height} to _ScreenSize's display_bounds()

It's kind of annoying to have to copy/paste 6 or so lines of code any time I want to be able to import an external script, but it's better than having to copy the entire contents of the imported script.

Full examples can be seen in my new applescript github repository.

Helper method for loading peer scripts in applescript.

No comments:

Post a Comment