Script Libraries

This is the last part of my mini-series on refactoring your scripts, script libraries. (see also script properties, script handlers, and script objects) So you’ve written a really nifty little script routine. You think it’s a really slick little way to do something, or perhaps the code it contains is ugly and you never want to look at it again. You wrapped it in a script handler or object, and now you want to copy and paste that code into many scripts to come. STOP! Before you start stretching you’re fingers between command and c, let me show you a nice way to share your code around with script libraries. If you haven’t read on script object basics, or don’t understand what a script object is, perhaps you should read that first.

One particularily ugly piece of scripting, but one that gives SO much power to the applescripter is access to the unix tools “under the hood” of the gorgeous aqua interface. The thing that makes it ugly though is the intermingling of strings and option flags that you have to remember. I should say though, that I really like the tools and was an avid *nix user for a while so I know my way around sed, perl, and other semi-acronymicly named commands. Learning a new one though is a pain, and I actually only really know the subset of it’s functionality I use often. Let’s look at one great tool that could benefit from being wrapped up nicely: defaults. Defaults lets you get and set values for the User Defaults system (user preferences). It stores it’s values in plist files in the ~/Library/Preferences directory. The User Defaults system is used by almost every application and even the operating system itself to store configuration information. By using this tool we can store data for our scripts in a standard place, as well as tweak the system we’re running in. Let’s look at my object wrapper:

script SimpleUserDefaults
	on getValue(domain, defaultsKey)
		return my PRIVATEdoIt("read", domain, defaultsKey, "")
	end getValue
	on setValue(domain, defaultsKey, newValue)
		return my PRIVATEdoIt("write", domain, defaultsKey, newValue)
	end setValue
	on PRIVATEdoIt(readWrite, domain, defaultsKey, newValue)
		set oldTIDs to text item delimiters
		set text item delimiters to " "
		set shellScript to {"defaults", readWrite, domain, defaultsKey, newValue} as string
		set handlerResult to do shell script shellScript
		set text item delimiters to oldTIDs
		return handlerResult
	end PRIVATEdoIt
end script

So now we have a beautiful little script object, with all the bells and whistles, hiding the complexities of unix for us behind a applescript facade. To use it we could write some thing like tell SimpleUserDefaults to [color=purple]setValue/color or some such thing. But now we want to use it to access preference data in other scripts… Let’s make it into a script library so that we can use it anywhere. Sounds complex Not at all! Just save the file (remove the highlighted “script SimpleUserDefaults” and “end script” lines when saving though… or click here) in a script library folder. (for example “~/Library/Scripts/Library/”) Now when we want to use it in another script we use the Standard Additions’ Scripting Commands Suite’s load script command and poof the magic is done.

property SimpleUserDefaults : load script file ((path to scripts folder as text) & "Library:SimpleUserDefaults.scpt")

tell SimpleUserDefaults to getValue("", "EnableDebugMenu")

Easy as pie right. At any rate, I’ll never look at the man page again! Here’s the best part: say you discover some hidden bug in that nifty little script you stuck in a library. To fix it in EVERY script that makes use of the library, just edit the library once. In the copy-paste scenario you’d spend an awfull long time going through scripts, finding where you pasted in that code in the midst of other bits and making the edit. Ridiculous right… been there done that, no more! This finishes up the series on refactoring. Together with your knowledge of script properties, script handlers, script objects, and now script libraries, your scripting efforts will not be repeated, be more effiecient, easier to read later, and leave you wondering what to do with the rest of your weekend!