[go: up one dir, main page]
More Web Proxy on the site http://driver.im/

You’re looking at a draft of a chapter from a work in progress, tentatively titled Scripting Mac Applications With Ruby: An AppleScript Alternative, by Matt Neuburg.
Covers rb-appscript 0.6.1. Last revised Sep 06, 2012. All content ©2012 by the author, all rights reserved.


Next: Installation and Usage
Contents

Introduction

Back in 1993, Apple Computer introduced a truly clever innovation: a way for ordinary users to write little programs (scripts) that would tell applications what to do. Tasks that would be repetitive, boring, calculation-intensive, error-prone, or virtually impossible if performed by hand suddenly became available through a single quick and accurate step — namely, running a script.

For example, suppose we want to create a text file listing the names of all the files on the Desktop. It would be tedious to copy (or type!) the name of each file, one at a time. Instead, we just run the following script and presto, there’s our file.

tell application "Finder"
    set L to get name of every file
    set f to choose file name default name "filelist.txt" default location (desktop as alias)
    open for access f with write permission
    set eof f to 0
    repeat with aName in L
        write aName & return to f
    end repeat
    close access f
end tell

Or suppose we want to assign all the tracks in an iTunes playlist to a single album and number the tracks incrementally. Track numbering is important; yet there is no Number Tracks command built into iTunes. It would be tedious (and error-prone, and boring) to fill in the track numbers one at a time. Instead, we just run the following script and presto, our tracks are numbered:

tell application "iTunes"
    display dialog "Album Name:" default answer "My Album"
    set albumName to text returned of result
    tell view of browser window 1
        set total to count file tracks
        repeat with i from 1 to total
            tell file track i
                set album to albumName
                set track count to total
                set track number to i
            end tell
        end repeat
    end tell
end tell

All of this is possible because the Finder and iTunes, like many other Mac applications, are scriptable. Not every Mac application is scriptable; but many are, and when an application is scriptable, it can be harnessed programmatically, induced to perform actions automatically through the running of a script.

Scriptability is a wonderful and powerful thing. It makes life better for you, the user. The messaging mechanism that underlies this type of scriptability, Apple events, is quite clever, allowing a single message packet to express such relatively complex concepts as name of every file or album of file track 1 of view of browser window 1. But the scripting language used to write these example scripts, AppleScript, has been a source of confusion, frustration and annoyance ever since it was invented.

This is not the place for a full discussion of all that I think is wrong with AppleScript. For that, you can consult my book AppleScript: The Definitive Guide. Yes, I wrote a huge and detailed book about AppleScript even though I dislike AppleScript! In fact, my dislike of AppleScript was the reason I wrote that book; I wanted to understand and explain precisely the many linguistic behaviors that I found so confusing, frustrating, and annoying. Here’s a brief list of some of AppleScript’s primary shortcomings:

There is an irony associated with many of these problems, in that they arise from good intentions. The idea, when AppleScript was being designed, seems to have been to make life easier for the novice AppleScript programmer. But in the end, I believe, AppleScript has emerged a quirky, troublesome language, with (in my view) a quality of being unfinished, “sent into this breathing world scarce half made up.”

All of these problems, and more, are solved through the approach taken in this book — the use of Ruby, along with Hamish Sanderson’s rb-appscript library, instead of AppleScript.

Ruby is an elegant, powerful language, created with an eye to the programmer’s convenience. It comes with superb handling of numbers, strings, arrays, hashes, and files, and is backed by numerous built-in and third-party libraries for performing tasks common and uncommon, such as parsing and building XML, communicating over a network, transforming image files, and talking to databases. A Ruby script is “just text”, so it can always be read and edited. With rb-appscript the difference between the mere formation of a reference and the actual sending of a communication to a scriptable application is crystal clear, there is never a doubt as to what scriptable application (or scripting addition) you’re talking to, namespaces remain clear and separate, and there is no such thing as a terminology conflict.

Once upon a time, my favorite way of scripting Macintosh applications was through a different alternative to AppleScript, namely UserTalk, the programming language of UserLand Frontier, about which I also wrote a book (http://sbc.apeth.com/frontierDef/ch00.html). But that was a long time ago; since then, Frontier’s abilities to send and receive Apple events have not kept pace with developments in the Mac OS X world, such as the advent of Intel-based Macintosh hardware, and various recent changes in the AppleScript language.

With the emergence of rb-appscript as a way of sending Apple events (which is remarkably similar, linguistically, to UserTalk’s mode of expression), my happiness is complete. I started using rb-appscript not long after the second edition of my AppleScript book was published, and became so excited that I wrote an article about it (http://www.oreillynet.com/pub/a/mac/2007/02/27/replacing-applescript-with-ruby.html). The decisive moment came when I was asked by the publishers of the Take Control ebooks to write some scripts automating parts of their publishing workflow, which used Microsoft Word. Things that were difficult to express linguistically or algorithmically in AppleScript suddenly became easy when I switched to Ruby and rb-appscript, and maintenance and development, which had been a nightmare, became a breeze. Since then, I’ve used rb-appscript for all my Macintosh application scripting; I virtually never use AppleScript any more.

Not only does rb-appscript let you communicate with Macintosh applications as an alternative to AppleScript, but also the fact that you’re using Ruby means you don’t need to communicate with Macintosh applications as much. AppleScript has few native abilities, so you generally need to be targeting some scriptable application in order to get anything done; but Ruby is extremely capable on its own. As a simple example, there is much less need to target the Finder with rb-appscript than with AppleScript, because Ruby already has excellent file-handling capabilities. Similarly, to perform image file transformations, you probably wouldn’t bother launching GraphicConverter or Photoshop and figuring out how to script them; you might instead access ImageMagick through the RMagick library.

Another advantage of Ruby over AppleScript is its general acceptance in the wider world. AppleScript is a specialized, Mac-only language, with a flavor of not being a “real” scripting language. Use of AppleScript locks you into a dependency on Apple’s whims; AppleScript might be incapable of something you need, it might be buggy, it might change its behavior from one system version to the next in incompatible ways. Indeed, the nature and extent of Apple’s own future support for AppleScript is an open question; for example, Apple’s own AppleScript Studio appears to have received no internal support in many years, Apple has introduced its own “bridges”, similar to rb-appscript, as alternatives to AppleScript (see the Appendix), and promised improvements to the AppleScript language have never materialized. Ruby, on the other hand, is a mature, cross-platform, thoroughly modern scripting language; it is open source, and different versions can be installed on the same machine. Ruby programmers are in wide demand, including in the spheres of enterprise and Web applications (in large part thanks to the example set by Ruby on Rails, a widely used Web application framework). Thus, many companies already have an extensive Ruby-based workflow, and rb-appscript can be effortlessly slotted in.

Ultimately, though, I simply find Ruby with rb-appscript, quite apart from the immeasurably greater power of Ruby, to be linguistically easier, clearer, cleaner, and more reliable than AppleScript. That’s the main reason why this book is so much shorter than my AppleScript book! Much of the AppleScript book was consumed with discussion of the quirks and pitfalls of AppleScript as a language; with Ruby and rb-appscript, there’s none of that, so there’s much less to say.

For whom is this book written? I would imagine readers to fall roughly into three categories: refugees from AppleScript (like myself), either deliberately fleeing its quirks and inconveniences or tentatively seeking some plausible alternative; experienced Ruby programmers who want to incorporate Macintosh application scriptability into their toolbox; and programming neophytes with little or no prior experience of scripting Macintosh applications, who just want to get started. This book will probably be found most useful for those in the first two categories, but I hope it will prove helpful for the third as well.

I have tried to avoid using this book as a polemical soapbox for comparisons, invidious or otherwise. This Introduction does contain a little AppleScript-bashing, by way of justifying and explaining the book as a whole; but I promise that the rest of the book does not. It is true that I am enthusiastic about my subject, but it is not my intention to attempt to persuade AppleScript users to switch to rb-appscript, even though I think they might be much happier if they did. Habit is a great comfort, and straying beyond one’s comfort zone is uncomfortable; to some people, the English-like verbosity of a line of AppleScript code like this:

tell application "Finder" to set all_names to the name of every file

seem more congenial than the more mathematically dry and compact equivalent rb-appscript expression:

all_names = Appscript.app("Finder").files.name.get

And this apparent congeniality, together with the investment of years already spent in learning to navigate AppleScript’s treacherous shoals, will be enough for many long-time AppleScript users to continue piloting their familiar waters. Nevertheless, I am convinced that the future cannot be like the past, and that for a user wishing to communicate with scriptable applications on Mac OS X, there needs to be a way forward from AppleScript. Apple might surprise us all by modernizing AppleScript and endowing it with the proper powers and abilities of a full-fledged scripting language; but until then, rb-appscript shows us what such a way can look like. I find it a pleasure to use and I hope you will too.

Here’s an outline of the structure of this book:

Chapter 1: Installation and Usage
How to install rb-appscript (and, if necessary, how to update Ruby), and some places where you can run Ruby scripts.
Chapter 2: Just Enough Ruby
An introduction to the Ruby language, just sufficient to let you follow the examples in this book.
Chapter 3: Apple Events
Introducing Apple events, the messaging mechanism underlying application scriptability on Mac OS X. AppleScript sends Apple events, but instead we’re going to use Ruby and rb-appscript to send them.
Chapter 4: The Application Object
Your first rb-appscript code! Before you can do anything else you have to specify an application object to send Apple events to; so here’s how to do that.
Chapter 5: Properties and Elements
The art of scripting a Mac application with Apple events consists mostly of specifying objects in the scriptable application’s world. Here’s how you do that.
Chapter 6: Commands
An Apple event is a command, and a command is an Apple event. Here’s how you send a command to a scriptable application.
Chapter 7: Datatypes
How rb-appscript maps datatypes in the Apple event world to Ruby classes.
Chapter 8: The Dictionary
All about the scriptable application’s dictionary: how it works, how to read it, and how to understand it.
Chapter 9: Scripting Additions
How to send a command to a scripting addition with rb-appscript.
Chapter 10: Examples
And now the moment you’ve been waiting for: lots and lots of examples, many of them taken from real life, showing rb-appscript communicating with some popular scriptable applications.
Appendix A: Where to Go From Here
Where to learn more, other versions of Appscript, competitors to Appscript, that kind of thing.

Next: Installation and Usage
Contents

You’re looking at a draft of a chapter from a work in progress, tentatively titled Scripting Mac Applications With Ruby: An AppleScript Alternative, by Matt Neuburg.
Covers rb-appscript 0.6.1. Last revised Sep 06, 2012. All content ©2012 by the author, all rights reserved.

This book took time and effort to write, and no traditional publisher would accept it. If it has been useful to you, please consider a small donation to my PayPal account (matt at tidbits dot com). Thanks!