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 Jun 23, 2012. All content ©2012 by the author, all rights reserved.


Prev: The Dictionary
Next: Examples
Contents

Chapter 9: Scripting Additions

1. Calling a Scripting Addition Command

2. Viewing a Scripting Addition’s Dictionary

3. Specifying a Host Application

4. Cancellation in Dialogs

As explained in Chapter 3, a scripting addition (or osax, plural osaxen) is a resource containing code and a dictionary. A scripting addition’s dictionary defines primarily commands. Mac OS X comes with one very commonly used scripting addition, StandardAdditions.osax (located in /System/Library/ScriptingAdditions/), and many third-party scripting additions are available. (To install one, place it in a ScriptingAdditions directory, typically in your user ~/Library.)

Most scripting addition commands are intended to compensate for the paucity of the AppleScript language, adding rudimentary abilities to handle files, strings, numbers, and dates that are missing from AppleScript itself. One important reason for using Ruby is that it is amply supplied with abilities and libraries that AppleScript lacks, and therefore you are unlikely to need this kind of scripting addition command. You are more likely to use scripting additions that implement some sort of user interaction or feedback. The StandardAdditions.osax commands let you put up dialogs where the user can do such things as specify a folder, choose from a list, or be shown a message; you can also generate the system alert (beep) sound or make the computer speak text.

1. Calling a Scripting Addition Command

In rb-appscript, unlike AppleScript, scripting additions are not loaded automatically, and neither is the rb-appscript front-end module by which you access scripting addition commands. If you intend to use a scripting addition in your code, you must explicitly load the file osax.rb:

require 'osax' # might have to require 'rubygems' first

This brings the OSAX module into existence. To discover what scripting addition files are installed, call the scripting_additions class method:

require 'osax'
p OSAX.scripting_additions
#=> ["Adobe Unit Types", "Digital Hub Scripting", "StandardAdditions"]

To use a scripting addition command, first generate an OSAX::ScriptingAddition instance with new, supplying the name of the scripting addition file containing the desired command. The name is case-insensitive, and you should not include the .osax file extension (it will be stripped if present).

require 'osax'
sa = OSAX::ScriptingAddition.new("standardadditions")

Note: If you’re running on Snow Leopard, you may get an error when you try to run that script, warning that “OSAX::ScriptingAddition can’t dynamically retrieve scripting addition terminology within a 64-bit process.” The solution is to force Ruby to run in 32-bit mode, which is easily done: simply start any script that uses the OSAX module with this line:

#!/usr/bin/arch -i386 ruby

For all remaining scripts in this chapter and the next that use OSAX, assume that the above line stands at the start if running on Snow Leopard.

As a shortcut, you can generate the same OSAX::ScriptingAddition instance by calling the osax class method instead:

require 'osax'
sa = OSAX.osax("standardadditions")

As an even shorter shortcut, if the scripting addition file you want to access is StandardAdditions.osax (which it probably will be), you can omit the parameter:

require 'osax'
sa = OSAX.osax

You can now issue a command by sending a method call to this OSAX::ScriptingAddition instance. The syntax is the same as for any command (described in Chapter 6).

require 'osax'
sa = OSAX.osax
sa.say "Good morning."

The osax class method is not merely a convenience form of ScriptingAddition.new. In the case where you call it with no parameters, as shown above — and only in that case — it caches the OSAX::ScriptingAddition instance the first time it is called (as a class instance variable), and returns the cached instance on subsequent calls. Thus there is no inefficiency in code like this:

require 'osax'
OSAX.osax.beep
OSAX.osax.say "Hey, wake up." # same ScriptingAddition instance

However, in any other case, it is up to you to retain the OSAX::ScriptingAddition instance and reuse it as needed.

2. Viewing a Scripting Addition’s Dictionary

ASDictionary works on scripting additions, so you can use it to choose a scripting addition file and generate a dictionary presentation. Alternatively, you can use an AppleScript-based dictionary presentation (such as Script Debugger or Script Editor).

The help command doesn’t work on an OSAX::ScriptingAddition instance, but you can use the introspective instance methods commands, which lists all commands, and parameters, which lists the parameters for the specified command:

require 'osax'
sa = OSAX.osax
p sa.commands
#=> ["ASCII_character", "ASCII_number", "activate", "adding_folder_items_to", "beep", ...]
p sa.parameters("display_alert")
#=> ["as", "buttons", "cancel_button", "default_button", "giving_up_after", "message"]

3. Specifying a Host Application

A scripting addition command is executed within the context of some application or process. If you don’t specify such a context (and none of the above examples do so), that context is the current process, which in this case is probably Ruby. To specify a different context, send an OSAX::ScriptingAddition instance one of the same methods you use to specify an application (see Chapter 4):

by_name
by_id
by_creator
by_pid
by_url

The result is a different OSAX::ScriptingAddition instance, one whose commands are executed in the context of the application you specified. The application acts as a host for commands sent to this OSAX::ScriptingAddition instance.

require 'osax'
finder_osax = OSAX.osax.by_name("Finder.app")

As a shortcut, instead of calling by_name explicitly, you can supply the application’s name as a second parameter to the osax class method:

require 'osax'
finder_osax = OSAX.osax nil, "Finder.app" # nil first parameter means StandardAdditions.osax

If the scripting addition command you intend to call presents some sort of visible interface such as a dialog, specifying an application context is a really good idea. Otherwise, rb-appscript must turn Ruby itself into a GUI application, which involves extra overhead. Besides, if the user is already looking at or working with some application, it probably makes sense to cause the dialog to appear within that application.

require 'osax'
f = OSAX.osax(nil, "Finder.app")
f.activate # note this technique
f.display_alert "Not So Fast", :message => "Comb your hair first."

Observe that the activate command works; although apparently sent to the OSAX::ScriptingAddition instance, it is routed to the host. This is true for all the built-in commands discussed in the last section of Chapter 6.

4. Cancellation in Dialogs

The standard scripting addition commands that generate dialogs all raise an exception if the user cancels out of the dialog:

require 'osax'
f = OSAX.osax(nil, "Finder.app")
f.activate
f.display_alert "Not So Fast", 
  :message => "Comb your hair first.", 
  :buttons => ["Cancel", "OK"],
  :cancel_button => "Cancel"
 # user presses the Cancel button
 #=> Appscript::CommandError: CommandError OSERROR: -128 MESSAGE: User canceled.

Handling this exception is up to you, if you want to prevent it from percolating up to top level and bringing your code to an untimely halt. The Appscript::CommandError instance’s to_i method will reliably yield -128 if the user cancels.

require 'osax'
f = OSAX.osax(nil, "Finder.app")
f.activate
begin
  f.display_alert "Not So Fast", 
    :message => "Comb your hair first.", 
    :buttons => ["Cancel", "OK"],
    :cancel_button => "Cancel"
rescue Appscript::CommandError => e
  exit if e.to_i == -128 # user cancelled, quit in good order
  raise e # something else happened
end
 # if we get here, the user didn't cancel

Prev: The Dictionary
Next: Examples
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 Jun 23, 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!