The Cocoa Scripting layer makes it extremely easy to expose manipulation of your application’s model to users via AppleScript. That said, for most developers the learning curve associated with this can be far from “easy.” The psychological burden of tackling scripting support seems to prevent many developers, even those within Apple, from providing even the barest of scripting support for their applications.
The promise of Cocoa Scripting is essentially that some robust AppleEvent parsing code in the Cocoa frameworks will translate the “yucky, raw events” into method dispatches that “just work” with your application’s attribute-based data model. Then, a different chunk of robust code will take the Cocoa objects that your application works with and automatically translate them into suitable AppleScript representations. For instance if you expose an NSString attribute from your application’s data model, the text contents are automatically converted to an AppleScript-native format suitable to the scripter’s needs. Similar bridging is done for objects as complex as windows and documents.
The power of this adaptive layer can be witnessed by taking an otherwise unscriptable application and “throwing the switch” that gives Cocoa permission to take over scripting. If you’ve got an unscriptable Cocoa-based application, why not use this as an opportunity to get your feet wet? In fact, Apple ships a good case study for this in Preview, so I’ll use that as a guinea pig while you follow along with whatever app you like. (thanks to John Gruber for pointing out this shortcoming and inspiring this article). Take the following script and paste it into Script Editor:
When you run the script, even if you can see an open document in Preview, you’ll be met with a rather rude reply: “Can’t get name of document 1.” Please! You’re telling me you can’t even offer me that tiny glimpse into the application’s personal details? Unfortunately Apple didn’t “flip the switch” on Preview, so none of the easy freebies from Cocoa Scripting are exposed through it.
So let’s flip the switch for them. Let’s pretend we work for Apple in the Preview group and our manager has finally given us the go ahead to investigate AppleScript support for Preview. Heck, let’s assume we’re the new intern, it’s day one, and we haven’t even been given source code access yet!
By navigating into the Preview.app package and opening the Info.plist document in Property List Editor (or an editor of your choice), we can add the requisite flag that instructs Cocoa Scripting to take over:
Now quit and relaunch both Preview and the Script Editor. Paste your example “name of document 1” script again and observe that the frontmost document’s name is returned!
Now you may be thinking, “Who cares? It’s just the title of the document, that’s not very useful.” But that’s not for you to decide! Let the script author decide. They’re the ones who have to use your program to get something done. The big deal here is that we turned an unscriptable application into a “scriptable beta” with the addition of a single Info.plist attribute. We didn’t even have to add a scripting dictionary!
Lest you think that the standard Cocoa Scripting functionality is only the name of the document, I will share a slightly more complex (albeit still contrived) example. Let’s suppose we have a hundred documents to review by hand with Preview. Based on some human-observable trait we want to open 25% of those documents later in Safari for printing or whatever. One option would be to go through and save a copy of each such document to a separate directory. When we’re done with the grueling day of work, we’ll drag the contents of that separate directory to Safari (or whatever application).
Using AppleScript and the “newly scriptable” Preview application, we can simplify this workflow by making the assumption that “any document with a tiny window” should be opened in Safari. Now as we go through the open documents one by one, we simply drag-resize the window to be less than 400 pixels wide. Later on, we run the following script, which makes a list of all such windows and opens the corresponding documents in Safari:
All of this for free! We make a kick-ass intern! And all on our first day with no source code.
By no means am I suggesting that developers should just flip the switch and ship. It’s very frustrating to see unscriptable apps, but even worse when a product claims scriptability but for all practical purposes is not. The point of this entry is merely to point out that Cocoa gives us a huge head start towards a decent scripting implementation, and to choose not to take advantage of that is cruel and unusual punishment to your users.
Just think how cool Preview will be when we add a dictionary that describes its document object model’s custom attributes.