Thursday, April 3, 2008, 04:55 AM -
Programming & ComputersPosted by Administrator
Automating page layouts, even highly templatized ones, is not a trivial task. Doing this kind of a thing is something sometimes bragged about by design and marketing firms on Apple's site. But the actual work and resulting pitfalls involved are conveniently glossed over in the article. This post is about that topic. I'm going to dig deep into an actual production problem I'm working on that has exploded in front of me. This is going to be 1 part rant, 1 part brag, and 1 part "Hopefully, some other hapless Applescript developer will read this and get something out of it and avoid the same pitfalls I've run into."
I'm currently working on a couple composition automation projects at The Day Job that uses
REALbasic,
Applescript, XML, and XSLT to do it all. When I am in the code it all makes sense. When I stand back from it for a minute and look at what is being done, or try to explain it to people, it is absolutely maddening. When it works, it is actually fun to watch. When it is not working, I can get lost in the code for days sometimes no matter how much of Code Complete's canon I have followed. This is something that I've dine in past for other projects, but nothing at the current scale or scope. It sounds as if I am bragging (about it working, not about the endless hours in code). Perhaps I am subconsciously. But, at the same time, I wish I didn't have to use all of this language buzzword bingo to accomplish (essentially) one task: automating a marketing piece (e.g. a postcard).
Where I'm having the most trouble is with
Applescript, and some of its weaknesses, both in the language and the community (Apple included), really shows here. Here is how it all plays out...
All of the Marketing information about The Day Job's products are stored a SQL database. The content gets downloaded to an XML file using a generic DTD. In my application, the XML file gets converted with XSLT to another XML file that is suited to the type of piece it is. An
Applescript is run that takes the transformed XML file and places the information into a specially prepared template that gets collected and saved to another location. This isn't exactly rocket science, I'm sure other companies are doing this. If not, I am available for consulting gigs. Just shout.
REALbasic, I think, has done a marvelous job of integrating
Applescript into a compiled app. I can run it as a command, method, or function, even with arguments. Troubleshooting the
REALbasic portion of the application is a cinch with all of the debugging tools contained in the IDE. It is brilliant, and I hope it is a feature that they never, ever deprecate. It is troubleshooting the
Applescript where all hell breaks loose.
Applescript isn't even nearly close with what
REALbasic can do. Not that I ever expect
REALbasic to help me troubleshoot my Applescripts other than if it is there or not, but again I expected better of Apple in the recent upgrade to Leopard.
If you use
Applescript in a professional capacity, then you more than likely use Script Debugger. If you don't, you do
not know what you are missing. Apple's Script Editor gets the job done, but Script Debugger does it way better (and I think Apple knows this given how little the Script Editor has changed). It, more or less, offers many of the same tools that
REALbasic's IDE does, and by result the scale of a script can grow considerably. I have some scripts that are 2000+ lines of code, and have created combined processes that are 3000+.
I've tried a couple times to use
Applescript Studio (essentially XCode) to create and debug scripts. I was shocked to see that XCode didn't offer the same tools to
Applescript as it does to other languages.
Applescript Studio, near as I can tell, is just a wrapper for the Script Editor for (loose) integration with Interface Builder through XCode. So, really, it has a "who cares" kind of a vibe to it, and simply accomplishes reinforcing my feeling that Apple views
Applescript as the red-headed step-child. I understand that
Applescript Studio/XCode is free, but I think Apple should have done better. I might as well stick with Script Editor. If Script were a hammer being used to kill the Problem Ant, then
Applescript Studio is a nuclear bomb without a guidance system to kill the Problem Ane. Just for the sake of argument, I run into Automator's limitations far too quickly for it to be useful (really, once you can code your own, there is no going back). The upgrade
Applescript got in Leopard seems more of "Oops, sorry about that, guys" than anything. A lot of those things they upgraded really should have been done ages ago. But, I digress...
As a result of this workflow, I'm working with a lot of files: two XML files, one XSLT, on InDesign template, all multiplied by the number of templates being supported (and then multiplied by the number of marketing pieces being created at any given time). So, I rely a lot on file paths, and by result I have a very strict folder structure.
Applescript treats file paths relative to the application that is running a given script. For example:
- If a script is running as an application...
- ...then all paths are relative to itself.
- ..., but I can't use it as a method or function through REALbasic; only a command, and that reduces its usefullness tremendously.
- If a script is run through an application (e.g. a REALbasic app)...
- ...then all paths are relative to that application.
- ..., but oftentimes I need to run the script through the Script Editor to troubleshoot the script, so no arguments or returned values in that context.
- If a script is running through the Script Editor...
- ...then paths are relative to the Script Editor...
- ..., but this is the only place where I can troubleshoot the script itself.
I can understand why Apple did what they did. Rather than limiting the developer to a single point of entry for file paths through the framework, they just let the developer deal with it. That might be an amatuerish way of looking at it, but it works for me. So, to work around this, I keep the script necessary for paging in a special folder in all of my paging applications, and I place in the script this subroutine:
on GetPathToMe()
set pathToMe to (get path to me) as string
set Applescript's text item delimiters to ":"
set pathArray to (every text item in pathToMe) as list
set Applescript's text item delimiters to ""
set CreationFolderPath to ""
repeat with x from 1 to ((get count of items in pathArray) - 1)
set thisDirectory to item x of pathArray
set CreationFolderPath to CreationFolderPath & thisDirectory & ":"
end repeat
return CreationFolderPath
end GetPathToMe
The "1" being subtracted in the upper limit for the
repeat block is how deep in the script's path I want to go. I can stop at the main folder, or I can stop at the script. This, combined with another subroutine that pieces different paths together to get me what I finally need, has been a massive relief in sorting out all of the path issues.
However, when I work on a script and save it in Script Debugger, Script Debugger does something, probably a wrapper, that causes the file to be "un-openable" in the Script Editor. If Script Editor can't open it, then
REALbasic can't open it either, because I'm sure it is hooking into the same framework that Script Editor and XCode are as well. So, to get around this, I have to go through some pretty extreme gyrations to troubleshoot the script. Actually, I have two versions of the same script. One is the script that is linked to the
REALbasic application. This is what I call the RUNTIME script. The second is a script that I have in Script Debugger for troubleshooting so I can easily all of those bits that Script Editor hides from me. That one I call the DEV script.
I write very subroutine heavy
Applescript code. I think it's the only way to fly. Every large script I write starts with an "on run" block. The "on run" block is there to quickly get the input and the script parameters to where they need to be. This allows it so that when I make changes to the DEV script, all I need to do is copy and paste all of the other subroutines from the DEV script into the RUNTIME script with minimal hassle, and minimize the bugs. At least that is the theory. Practice always yields some scenario that I didn't think of before, because the problem is that I'm forced to copy and paste as part of the build and test process.
I've looked at this every which way, and I can't sort out any other
feasible way around this problem. (There are other issues that I know could be made easier, like talking to the database directly as opposed to creating that first XML file.) But, I say feasible rather pointedly because the unfeasible way would be to somehow incorporate
REALbasic and the Adobe Creative Suite. It is possible because
REALbasic can talk to scriptable applications with AppleEvents, but not feasible because the number of different AppleEvents in this one script weighs in at 300+, and then there is the problem of storing objects in variables as well.
REALbasic has the AppleEventObjectSpecifier Class, so that
might do the trick. But, when to get to all of
that? There ought to be a better way.
It sure would be cool if all of the
Applescript stuff could be ported over into something more robust. I've heard of Javascript being another way to do it, but I have to say that I'm not a fan of the syntax, and that doesn't solve the problem of one too many languages. Then, I could do away with all of these Applescripts and reduce the number of languages by 25%. Let's see Apple talk about that on their site for a change.