ASObjC Runner — Vanilla Mode

ASObjC Runner is a scriptable faceless background helper application. Drag it to your Applications folder, launch it, and forget it. When you run it you can set whether it displays an icon and menu in the status area of your main menu bar, and whether it should regularly check for updates automatically.

ASObjC Runner's dictionary is divided into six suites: the Runner Suite, containing the application and general use commands, the String Suite, the List Suite, the File Suite, the Record Suite, and the XML Suite.

Runner Suite

The Runner Suite contains the application object, where you can get and set various properties. Properties related to the application itself are: automatically check for updates, frontmost, name, status menu is showing, and version. For example:

 tell application "ASObjC Runner"
 -- hide the status menu
 set status menu is showing to false
 end tell

There is also a property called modifier keys, which you can use to find out the state of the various modifier keys. You can get its properties in a single call, or query one of the properties representing a particular key. For example:

 tell application "ASObjC Runner"
  caps lock key down of modifier keys
  --> true
  properties of modifier keys
  --> {caps lock key down:true, shift key down:false, command key down:true, control key down:false, option key down:false, class:mod keys}
 end tell

There are five properties related to the log values command: log date format, log line separator, log padding values, log string format, and log value separator. You use these to specify the format used when you issue the log values command.

The progress window property is used to set the properties of the progress window you can display. You can set the window's name, whether it includes a button and its title, the message and detail, as well as various properties related to the progress bar. As of version 1.9.2, you can optionally have it display a second progress bar. Typically you set these properties before showing the progress window, and update them as your task proceeds.

Version 1.9.10 adds a new property, elapsed time, which can be used as a timer.

The application has two classes, items of which are elements of the application. They are mounted volume and screen.

You can get the properties of a screen like this:

 tell application "ASObjC Runner"
  properties of screen 1
  --> {id:69730752, bounds:{1920, 0, 4480, 1440}, has menu bar:true, dimensions:{2560, 1440}, usable offset:{0, 22}, index:1, main screen:true, virtual screen:false, usable dimensions:{2514, 1418}, usable bounds:{1920, 22, 4434, 1440}, class:screen}
 end tell

You can also retrieve individual properties, like this:

 tell application "ASObjC Runner"
  dimensions of screen 1 where has menu bar is true
  --> {2560, 1440}
  dimensions of last screen -- the last screen is the virtual screen, encompassing all screens
  --> {4480, 2640}
 end tell

You can also move the menu bar between screens, like this:

 tell application "ASObjC Runner"
  set has menu bar of screen 2 to true
 end tell

The mounted volume class can be used like this:

 tell application "ASObjC Runner"
  name of mounted volumes
  --> {"Macintosh HD"}
  name of mounted volumes whose visible is true
  --> {"Macintosh HD"}
  free space of mounted volumes whose visible is true
  --> {7.4526208E+11}
  properties of mounted volume 1 whose startup is true
  --> {capacity:9.99345127424E+11, volume reference:file "Macintosh HD:", ejectable:false, volume path:"/", class:mounted volume, format:"hfs", free space:7.45262088192E+11, name:"Macintosh HD", description:"hfs", visible:true, locked:false, unmountable:false, startup:true}
 end tell

There are nine commands in the Runner Suite. The first, run the script, is used to run AppleScriptObjC code. See the separate documentation on how to do this.

The check for update command is the equivalent of the one in the application's menu; it lets you check to see if a newer version is available.

The do trig on command is for trigonometric calculations. For example:

 tell application "ASObjC Runner"
 -- convert 45 degrees to radians
 set theAngle to 45 / 180 * pi
 do trig on theAngle using function "sin"
 --> 0.707106781187
 do trig on theAngle using function "tan"
 --> 1.0
 end tell

The log values command is a simple way to add logging to your scripts. When you call log values {x, y} using file someFile, the file will be created if necessary, and the values will be appended with the date and time, and formatted according to the relevant application properties. You can modify these to suit, and the reset logging defaults command will reset them. For example:

 set a to 10.5
 set b to "Some text"
 set c to 1.578
 set d to "Some more text"
 
 -- path where file will be created
 set aFile to ((path to desktop as text) & "Test log.txt")
 
 tell application "ASObjC Runner"
 reset logging defaults
 log values {a, b} using file aFile
 log values {c, d} using file aFile
 --> File contains:
 -->2012-04-03 21:52:56 10.5 Some text
 -->2012-04-03 21:52:56 1.578 Some more text
 
 -- set new log properties
 set properties to {log date format:"HH:MM:ss", log padding values:{8}, log string format:"<time>:  <values>."}
 log values {a, b} using file aFile
 log values {c, d} using file aFile
 --> File contains:
 -->22:04:41:  10.5     Some text.
 -->22:04:41:  1.578   Some more text.
 end tell

There are three commands related to the progress window: reset progress will reset all the relevant properties to their default values, show progress will display the window, and hide progress will close the window. Typically you issue the reset command, set the various progress window properties to suit, show the window, update it as your script progresses, then hide it. Here is a basic example:

 tell application "ASObjC Runner"
 -- set up dialog and show it
 reset progress
 set properties of progress window to {button title:"Cancel", button visible:true, message:"This is a sample", detail:"More text can go here", indeterminate:false, max value:10, current value:0}
 activate
 show progress
 end tell
 delay 0.5
 repeat with i from 1 to 10
 -- do your other stuff here
 delay 1 -- for effect
 -- update dialog
 tell application "ASObjC Runner"
 activate
 set properties of progress window to {detail:"This is number " & i, current value:i}
 if button was pressed of progress window then
 exit repeat
 end if
 end tell
 end repeat
 -- hide dialog
 tell application "ASObjC Runner" to hide progress

As of version 1.9.2, you can show two progress bars:

 tell application "ASObjC Runner"
  -- set up dialog and show it
  reset progress
  set properties of progress window to {button title:"Stop, I Want to Get Off", button visible:true, message:"This is a sample", detail:"More text can go here", indeterminate:false, max value:10, current value:0, bar two visible:true, max value two:10, current value two:0, detail two:"And here"}
  activate
  show progress
 end tell
 delay 0.5
 repeat with i from 1 to 10
  repeat with j from 1 to 10
  -- do your other stuff here
  delay 0.1 -- for effect
  -- update dialog
  tell application "ASObjC Runner"
  activate
  set properties of progress window to {detail:"This is number " & i, current value:i, detail two:"This is number " & j, current value two:j}
  if button was pressed of progress window then exit repeat
  end tell
  end repeat
  -- check again if button was pressed
  tell application "ASObjC Runner"
  if button was pressed of progress window then exit repeat
  end tell
 end repeat
 -- hide dialog
 tell application "ASObjC Runner" to hide progress

The value for key path command is the equivalent of Cocoa's -valueForKeyPath: method. The key path is a string representing a property of the equivalent Cocoa item, or a dot-delimited relationship of properties. This command is most useful for lists of records. For example:

 tell application "ASObjC Runner"
  set sampleData to {{theFirst:"Fred", theLast:"Smith", theAge:59}, {theFirst:"Jane", theLast:"Anderson", theAge:60}, {theFirst:"Fred", theLast:"Avery", theAge:59}, {theFirst:"Ann", theLast:"Winters", theAge:58}}
  value for key path "theFirst" of item sampleData
  --> {"Fred", "Jane", "Fred", "Ann"}
  value for key path "@distinctUnionOfObjects.theFirst" of item sampleData
  --> {"Fred", "Jane", "Ann"}
  value for key path "@avg.theAge" of item sampleData
  --> 59.0
 end tell

String Suite

The modify string command has a range of functions. You can use it to change case, to smarten/dumb quotes, to pad and trim, to encode and encode for URIs, XML and HTML, to process comma-separated values, to calculate an MD5 hash, to perform ICU transforms, and to standardize POSIX paths. You can pass it a single string, or you can pass a list. In the case of a list, it will be searched recursively and the operation will be carried out on every string found; items of other classes in the list will not be touched. For example:

 set theString to " Hello: <b>\"world\"</b> "
 tell application "ASObjC Runner"
 modify string theString so it is caps
 --> " HELLO: <B>\"WORLD\"</B> "
 modify string theString so it is cap words
 --> " Hello: <B>\"World\"</B> "
 modify string theString so it is lower
 --> " hello: <b>\"world\"</b> "
 modify string theString so it is cap words
 --> " Hello: <B>\"World\"</B> "
 modify string theString so it is padded pad string ". " pad length 40
 --> " Hello: <b>\"world\"</b> . . . . . . . . "
 modify string theString so it is smart quoted
 --> " Hello: <b>“world”</b> "
 modify string theString so it is MD5 checksum
 --> "4ecf84a4689a54562f5fe829f708c251"
 modify string theString so it is encoded for XML
 --> " Hello: &lt;b&gt;&quot;world&quot;&lt;/b&gt; "
 modify string theString so it is trimmed
 --> "Hello: <b>\"world\"</b>"
 modify string theString so it is escaped URI
 --> "%20%20Hello:%20%3Cb%3E%22world%22%3C/b%3E%20"
 modify string theString so it is fully escaped URI
 --> "%20%20Hello%3A%20%3Cb%3E%22world%22%3C%2Fb%3E%20"
 
 modify string "~/Desktop//" so it is standardized POSIX
 --> "/Users/shane/Desktop"
 end tell

From version 1.9.2, you can provide a list of modifications, in the order you want them performed. For example:

From version 1.9.9, you can provide provide files (file references or aliases) instead of strings, and the command will operate on the contents of the files.

 set someString to " The TIME has come, for all GOOD men "
 tell application "ASObjC Runner"
  modify string someString so it is {lower, cap words, clean spaced}
  --> "The Time Has Come, For All Good Men"
 end tell

The look for command lets you search (and optionally replace) using regular expressions. Again, you can act on a single string or recursively on a list, and in version 1.9.9 and later, on the contents of files.

 tell application "ASObjC Runner"
 set whatToSearch to "one and Once and two and only three"
 -- search for "O" followed by two non-space characters
 look for "O\\S{2}" in whatToSearch
 --> {"Onc"}
 look for "O\\S{2}" in whatToSearch options "i" -- ignore case
 --> {"one", "Onc", "onl"}
 look for "O\\S{2}" in whatToSearch options "i" with invert -- invert search
 --> {"", " and ", "e and two and ", "y three"}
 look for "O(\\S{2})" in whatToSearch options "i" capture 1 -- return first capture
 --> {"ne", "nc", "nl"}
 look for "O(\\S{2})" in whatToSearch options "i" replacing with "Da$1" -- replace
 --> "Dane and Dance and two and Danly three"
 
 -- you can also search a list of strings
 set whatToSearch to {"one", "Once", "two", "three"}
 look for "O\\S{2}" in whatToSearch
 --> {{}, {"Onc"}, {}, {}}
 look for "O\\S{2}" in whatToSearch options "i" -- ignore case
 --> {{"one"}, {"Onc"}, {}, {}}
 look for "O\\S{2}" in whatToSearch options "i" with invert -- invert search
 --> {{}, {"", "e"}, {"two"}, {"three"}}
 look for "O(\\S{2})" in whatToSearch options "i" capture 1 -- return first capture
 --> {{"ne"}, {"nc"}, {}, {}}
 look for "O(\\S{2})" in whatToSearch options "i" replacing with "Da$1" -- replace
 --> {"Dane", "Dance", "two", "three"}
 
 -- you can also search and replace in a list recursively
 set whatToSearch to {1, "one", false, "Once", {1, 2, "ong"}, "three"}
 look for "O(\\S{2})" in whatToSearch options "i" replacing with "Da$1" -- replace
 --> {1, "Dane", false, "Dance", {1, 2, "Dang"}, "three"}
 end tell

The replace string command performs a literal find/change. The split string command lets you split a string (or strings) based on characters or another string, and link strings lets you join strings. If you pass a list to replace string, the replacement will carried out on all strings and files found in a recursive search of the list.

 tell application "ASObjC Runner"
 set whatToSearch to "one and Once and two and only three"
 replace string "and" in item whatToSearch replacing with "or"
 --> "one or Once or two or only three"
 replace string "On" in item whatToSearch replacing with "dan"
 --> "dane and dance and two and danly three"
 replace string "On" in item whatToSearch replacing with "dan" with case matters
 --> "one and dance and two and only three"
 split string whatToSearch with string "and"
 --> {"one ", " Once ", " two ", " only three"}
 split string whatToSearch with string "and" with only first
 --> {"one ", " Once and two and only three"}
 split string whatToSearch with string "ad" with by character
 --> {"one ", "n", " Once ", "n", " two ", "n", " only three"}
 link strings {whatToSearch, "four", "five"} by inserting " and "
 --> "one and Once and two and only three and four and five"
 end tell

Version 1.9.10 adds only first and only last parameters to the replace string command, and only last to the split string command.

With link strings you can also control whether to ignore empty strings, and you can pass it a list of equal-length lists and have them combined:

 tell application "ASObjC Runner"
  link strings {"one", "two", "", "", "three"} by inserting "*"
  --> "one*two***three"
  link strings {"one", "two", "", "", "three"} by inserting "*" with ignoring blanks
  --> "one*two*three"
  link strings {{"1", "2", "3"}, {"=", "=", "="}, {"one", "two", "three"}} by inserting " "
  --> {"1 = one", "2 = two", "3 = three"}
 end tell

The clean string command performs a series of clean-ups: it removes double spaces and spaces at the start and end of paragraphs, replaces two hyphens with an em-dash, and smartens quotes. It also has options for removing empty lines, dealing with tabs, using en-dashes with numerals, and removing tags. It will act on a single string or file, or a simple list of strings and/or files. For example:

 tell application "ASObjC Runner"
 set whatToSearch to " \"Hello, George,\" he said. \"Have you read 'War and Peace'?\" He knew he hadn't. \"No--it's number -43 on my list of things to do,\" he replied. "
 clean string whatToSearch with endashes before numerals and dashes spaced
 --> "“Hello, George,” he said. “Have you read ‘War and Peace’?” He knew he hadn’t. “No — it’s number –43 on my list of things to do,” he replied."
 end tell

As of version 1.9.5, clean string will also work on strings within lists and sublists.

The format date and format number commands give you complete control over the appearance of dates and numbers in text. You can format dates as local or UTC, and you control how numbers are rounded. You can even spell out numbers. For example:

 -- make a date
 set aDate to current date
 set day of aDate to 1
 set year of aDate to 2010
 set month of aDate to 6
 
 tell application "ASObjC Runner"
 format date aDate format "yyyy-MM-dd HH:mm:ss a"
 --> "2010-06-01 22:25:21 PM"
 format date aDate format "h:mm a, zzzz"
 --> "10:25 PM, Australian Eastern Standard Time"
 format date aDate format "h:mm a, z" with using UTC
 --> "12:25 PM, GMT+00:00"
 format date aDate format "'week' w 'of' yyyy, 'in the' QQQQ"
 --> "week 22 of 2010, in the 2nd quarter"
 
 format number 1.111E+4 format "#,###.#"
 --> "11,110"
 format number 1.111E+7 format "#,###.#"
 --> "11,110,000"
 format number -1.111E+7 format "#,###.0#;(#,###.0#)"
 --> "(11,110,000.0)"
 format number 11.245 format "$#.00" rounding as taught in school
 --> "$11.25"
 format number 11.235 with in words
 --> "eleven point two three five"
 end tell

If you pass it a list, the list will be searched recursively for dates/numbers, and they will all be replaced by formatted strings; all other classes will be unchanged. For example:

 set aDate to current date
 set aList to {}
 repeat with i from 1 to 5
 set aDate to aDate + 1
 set end of aList to {i, aDate}
 end repeat
 tell application "ASObjC Runner"
 format date aList format "mm:ss"
 --> {{1, "20:43"}, {2, "20:44"}, {3, "20:45"}, {4, "20:46"}, {5, "20:47"}}
 end tell

Version 1.9.9 introduces a new command, convert string. This lets you convert a string or strings to dates, integers, or reals. It is like a batch coercion facility, but with numerical strings you can choose to use the local decimal separator, and with dates you provide a format string for how to parse them. For example:

 tell application "ASObjC Runner"
  convert string {"2012-12-29", "2010-01-05", "1952-10-03"} format "yyyy-MM-dd"
  --> {date "Saturday, 29 December 2012 12:00:00 AM", date "Tuesday, 5 January 2010 12:00:00 AM", date "Friday, 3 October 1952 12:00:00 AM"}
  convert string {"1.023E+2", "12.34", "-1345"} with integer values without localized -- expects . as decimal separator
  --> {102, 12, -1345}
  convert string {"1.023E+2", "12.34", "-1345"} with real values and localized -- expects localized decimal separator
  --> {102.3, 12.34, -1345.0}
 end tell

List Suite

The rearrange list, rearrange lists of lists, rearrange files, and rearrange records commands are all sorting commands. For lists, you can set the sorting style (whether to match case, localize, or use Finder-style sorting), whether to make the list unique, and whether to sort in ascending or descending order. For lists of lists, you can choose the order of items to sort on, and with lists of records and lists of files you can choose the properties to sort on. For example:

 tell application "ASObjC Runner"
 rearrange list {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7}
 --> {1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9, 10}
 rearrange list {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7} without ascending
 --> {10, 9, 8, 7, 6, 5, 5, 5, 4, 3, 2, 1}
 rearrange list {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7} with unique
 --> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
 rearrange list {"one", "One", "Two", "two", "three"}
 --> {"one", "One", "three", "Two", "two"}
 --> {"one", "One", "three", "two", "Two"}
 rearrange list {"22 name", "21 name", "2 name", "1 name", "100 name"} sorting style like Finder
 --> {"1 name", "2 name", "21 name", "22 name", "100 name"}
 
 rearrange list of lists {{1, 2, "c"}, {2, 3, "e"}, {4, 3, "d"}, {3, 2, "b"}, {2, 2, "a"}, {1, 1, "z"}} by indexes {2, 3}
 --> {{1, 1, "z"}, {2, 2, "a"}, {3, 2, "b"}, {1, 2, "c"}, {4, 3, "d"}, {2, 3, "e"}}
 rearrange list of lists {{1, 2, "c"}, {2, 3, "e"}, {4, 3, "d"}, {3, 2, "b"}, {2, 2, "a"}, {1, 1, "z"}} by indexes {2, 3} ascending orders {true, false}
 --> {{1, 1, "z"}, {1, 2, "c"}, {3, 2, "b"}, {2, 2, "a"}, {2, 3, "e"}, {4, 3, "d"}}
 
 rearrange records {{theFirst:"Fred", theLast:"Smith"}, {theFirst:"Jane", theLast:"Anderson"}, {theFirst:"Fred", theLast:"Avery"}, {theFirst:"Ann", theLast:"Winters"}} by keys {"theFirst", "theLast"}
 --> {{theFirst:"Ann", theLast:"Winters"}, {theFirst:"Fred", theLast:"Avery"}, {theFirst:"Fred", theLast:"Smith"}, {theFirst:"Jane", theLast:"Anderson"}}
 rearrange records {{theFirst:"Fred", theLast:"Smith", theAge:59}, {theFirst:"Jane", theLast:"Anderson", theAge:60}, {theFirst:"Fred", theLast:"Avery", theAge:59}, {theFirst:"Ann", theLast:"Winters", theAge:58}} by keys {"theAge", "theFirst", "theLast"} ascending orders {false, true, true}
 --> {{theFirst:"Jane", theLast:"Anderson", theAge:60}, {theFirst:"Fred", theLast:"Avery", theAge:59}, {theFirst:"Fred", theLast:"Smith", theAge:59}, {theFirst:"Ann", theLast:"Winters", theAge:58}}
 end tell
 
 tell application "Finder"
 set theFiles to files of desktop as alias list
 end tell
 tell application "ASObjC Runner"
 rearrange files theFiles in order by modification date without ascending
 end tell

The refine list command lets you filter lists using predicates. These are similar to AppleScript whose/where filters, but potentially more powerful. These are a few examples:

 tell application "ASObjC Runner"
 refine list {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7} using predicates {"self between {6,8}"}
 --> {6, 8, 7}
 refine list {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7} using predicates {"not self between {6,8}"}
 --> {10, 3, 5, 2, 9, 4, 5, 1, 5}
 refine list {"one", "One", "Two", "two", "three"} using predicates {"self.length > 3"}
 --> {"three"}
 refine list {"one", "One", "Two", "two", "three"} using predicates {"self contains 'w'"}
 --> {"Two", "two"}
 refine list {"one", "One", "Two", "two", "three"} using predicates {"self contains 'w'", "not self contains 'T'"}
 --> {"two"}
 refine list {"one", "One", "Two", "two", "three"} using predicates {"self contains 'T'"}
 --> {"Two"}
 refine list {"one", "One", "Two", "two", "three"} using predicates {"self contains[cd] 'T'"} -- ignore case
 --> {"Two", "two", "three"}
 refine list {"one", "One", "Two", "two", "three"} using predicates {"self matches '.n.'"} -- regular expression
 --> {"one", "One"}
 end tell

The look in list command lets you search a list, returning the offset of matching items:

 tell application "ASObjC Runner"
 look in list {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7} matching 5
 --> {4, 8, 11}
 look in list {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7} matching 5 with inverting
 --> {1, 2, 3, 5, 6, 7, 9, 10, 12}
 look in list {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7} matching 5 with only first
 --> {4}
 look in list {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7} matching 11 with only first
 --> {}
 look in list {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7} matching items {3, 5}
 --> {2, 4, 8, 11}
 end tell

The summarize numbers command will return the minimum, maximum and sum of a list of numbers:

 tell application "ASObjC Runner"
 summarize numbers {10, 3, 6, 5, 2, 9, 4, 5, 8, 1, 5, 7}
 --> {65.0, 10.0, 1.0}
 end tell

The modify list command has a range of options: you can add padding, convert columns to rows, delete and trim blank items, delete, move, merge and insert items, swap items, and intersect with, or subtract from, another list. You can also remove any duplicate entries. For example:

 tell application "ASObjC Runner"
 modify list {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}} with cols to rows
 --> {{1, 4, 7, 10}, {2, 5, 8, 11}, {3, 6, 9, 12}}
 modify list {1, 2, 3, 4, 5} deleting indexes {2, 4}
 --> {1, 3, 5}
 modify list {1, 2, 3, 4, 5} inserting items {13, 14} before index -2
 --> {1, 2, 3, 13, 14, 4, 5}
 modify list {1, 2, 3, 4, 5} inserting item {13, 14} before index 3
 --> {1, 2, {13, 14}, 3, 4, 5}
 modify list {1, 2, 3, 4, 5} swapping indexes {1, -1}
 --> {5, 2, 3, 4, 1}
 modify list {1, 2, 3, 4, 5} subtracting list {2, 4}
 --> {3, 5, 1}
 modify list {1, 2, 3, 4, 5} intersecting with list {2, 4, 6, 7}
 --> {2, 4}
 modify list {1, 5, 2, 5, 3, 2, 4, 5} with making unique
 --> {1, 5, 2, 3, 4}
 modify list {1, 2, "", 3, {}, 4, missing value, {"", "", {}}, 5} with removing blanks
 --> {1, 2, 3, 4, 5}
 end tell

In the next example, empty columns in the data are removed:

 tell application "ASObjC Runner"
  modify list {{"a", "b", "", "", "e"}, {"aa", "", "", "dd", "ee"}} ¬
  with cols to rows, removing blanks and xtra cols to rows
  --> {{"a", "b", "", "e"}, {"aa", "", "dd", "ee"}}
 end tell

Version 1.9.5 adds a new parameter, replacing nulls with, which takes a string. This replaces instances of missing value with the provided string.

File Suite

Where commands say they will accept a file or list of files, a file means a file or folder unless the context suggests otherwise. A file can be an alias, a file reference, a colon-delimited (HFS) path like "Macintosh HD:Folder:File", or a POSIX path. POSIX paths must begin with a /. (You can use modify string aPath so it is standardized POSIX to expand a leading ~.) Where commands return files or lists of files, the files will be «furl» objects.

Where you supply extensions, or are returned extensions, they must not contain the leading stop (or stops anywhere, for that matter). The manage file command is for for copying/moving/deleting files and folders, and creating alias files, folders, hard links, symbolic links and archives. You can control whether to overwrite existing items, and whether to delete completely or move to the trash. Here is an example of creating folders:

 set folderPath to ((path to desktop as text) & "Folder 1:Folder 2:Folder 3:Folder 4")
 tell application "ASObjC Runner"
 manage file folderPath with creating folders
 end tell

The file path from command gives you easy ways to manipulate file paths and names. You can add, delete and replace extensions, insert text at the end of a name but before the extension, and remove components. You don't have to worry about issues such as trailing colons in folder and package paths. Here it is used along with manage file:

 tell application "ASObjC Runner"
 activate
 -- choose a file
 set theFile to (choose file with prompt "Choose file to duplicate and rename")
 -- make new path
 set newPath to file path from theFile inserting "_2"
 -- duplicate file with new name
 manage file theFile copying as newPath overwriting no -- use 'no silently' to silence error
 end tell

The overwriting parameter of manage file has four options: yes, which means any existing file will be overwritten; no, which means the command will return an error if a file of the same name already exists; no silently, which means the existing file will not be overwritten, but there will be no error so the command will continue on to any other files it is moving or copying; and no rename, which means it will insert -# before the extension, where # is the lowest integer that makes a unique name.

The parsed path command is used to parse an HFS or POSIX path into various components. It gives you an easy way to build new paths from existing ones.

 tell application "ASObjC Runner"
  parsed path "Macintosh HD:Users:shane:Desktop:Some script.scpt"
  --> {name extension:"scpt", name stub:"Some script", path components:{"Macintosh HD", "Users", "shane", "Desktop", "Some script.scpt"}, name:"Some script.scpt", containing item:"Macintosh HD:Users:shane:Desktop", name stub path:"Macintosh HD:Users:shane:Desktop:Some script"}
  parsed path "/Users/shane/Desktop/Some script.scpt"
  --> {name extension:"scpt", name stub:"Some script", path components:{"/", "Users", "shane", "Desktop", "Some script.scpt"}, name:"Some script.scpt", containing item:"/Users/shane/Desktop", name stub path:"/Users/shane/Desktop/Some script"}
  name stub path of (parsed path "Macintosh HD:Users:shane:Desktop:Some script.scpt")
  --> "Macintosh HD:Users:shane:Desktop:Some script"
  containing item of (parsed path "Macintosh HD:Users:shane:Desktop:Some script.scpt")
  --> "Macintosh HD:Users:shane:Desktop"
 end tell

The enumerate folder command will return the contents of a folder, including subfolders if you wish. You can filter the result by a range of properties, including extension, modification date, creation date and last access date, as well as variations on the name (match part of the name, match the suffix, match the prefix, and match a regular expression). The results can be a list of files or a list of POSIX paths. This example uses it to get the files in a folder, and then uses manage file to make a new folder and copy the files into it:

 tell application "ASObjC Runner"
 activate
 -- get list of files
 set theFiles to enumerate folder (choose folder with prompt "Choose folder with files to copy")
 -- get path for new folder
 set folderPath to ((path to desktop as text) & "ASObjC test folder")
 -- create the folder
 manage file folderPath with creating folders
 -- copy the files to the new folder
 manage file theFiles copying into folderPath overwriting no -- use 'no silently' to silence error
 end tell

This is an example of recursive enumeration, and using the file path from command to swap the extensions. The file path from command returns the modified names; it does not change the actual files.

 tell application "ASObjC Runner"
 activate
 -- get list of files
 set theFiles to enumerate folder (choose folder with prompt "Choose folder with files") match extensions {"txt"} with recursion
 -- swap extensions
 set newPaths to file path from theFiles replacing extension "txtx"
 end tell

The about file command will return a record containing information about a file or folder. Set the directory size parameter to false to avoid calculating the size of a folder if you don't need it:

 tell application "ASObjC Runner"
 activate
 set theFile to (choose file with prompt "Choose file ")
 about file theFile
 --> {container:file "Macintosh HD:Users:shane:Desktop:", locked:false, physical size:86016, group privs:"r--", displayed name:"Test file.pdf", symbolic link:false, alias original:missing value, type identifier:"com.adobe.pdf", owner:"shane", kind:"Adobe PDF document", directory folder:false, name:"Test file.pdf", name extension:"pdf", size:82494, group:"shane", modification date:date "Friday, 20 April 2012 3:08:46 PM", alias status:false, owner privs:"rw-", last access date:date "Monday, 23 April 2012 10:24:50 AM", name stub:"Test file", link count:1, default application:file "Macintosh HD:Applications:Adobe Acrobat X Pro:Adobe Acrobat Pro.app:", package folder:false, label index:0, stationery:false, disk:file "Macintosh HD:", visible:false, creation date:date "Friday, 20 April 2012 3:08:46 PM", everyones privs:"r--"}
 end tell

As of version 1.9.5, about file has a new property, POSIX path, and a new optional parameter, include only, which takes a list of the names of properties to include in the reply. The command will also now accept a list of files.

The modify file command will let you change properties including the name, label, stationery status and locked status of a file:

 tell application "ASObjC Runner"
 activate
 set theFile to (choose file with prompt "Choose file (it will be modified; don't pick anything valuable)")
 -- make sure it's unlocked
 modify file theFile without setting locked status
 -- change extension and Finder label, then lock
 modify file theFile setting extension "xyztest" setting label index 2 with setting locked status
 end tell

The test for equality command can be used to compare two or more files for equality:

 tell application "ASObjC Runner"
 activate
 -- get list of files
 set theFiles to enumerate folder (choose folder with prompt "Choose folder with files")
 set resultBoolean to test for equality {item 1 of theFiles, item 1 of theFiles}
 --> true
 set resultBoolean to test for equality theFiles
 --> false
 end tell

The save plist to and read plist at commands can be used to read and write lists and records to files. The lists must be restricted to text, numbers, booleans, dates, and data. The binary format parameter specifies whether to save the file in the smaller binary format. For example:

 tell application "ASObjC Runner"
 set someList to {{theFirst:"Fred", theLast:"Smith"}, {theFirst:"Jane", theLast:"Anderson"}, {theFirst:"Fred", theLast:"Avery"}, {theFirst:"Ann", theLast:"Winters"}}
 set anotherList to {1, 2, 3, "Hello", 4, "World", (current date), true}
 set someRecord to {theFirst:"Fred", theLast:"Smith"}
 activate
 set theFile to (choose file name with prompt "Save file to" default name "Untitled.plist")
 save plist to theFile containing someList
 read plist at theFile
 --> {{theFirst:"Fred", theLast:"Smith"}, {theFirst:"Jane", theLast:"Anderson"}, {theFirst:"Fred", theLast:"Avery"}, {theFirst:"Ann", theLast:"Winters"}}
 save plist to theFile containing someRecord
 read plist at theFile
 --> {theFirst:"Fred", theLast:"Smith"}
 save plist to theFile containing anotherList with binary format
 read plist at theFile
 --> {1.0, 2.0, 3.0, "Hello", 4.0, "World", date "Wednesday, 4 April 2012 5:16:28 PM", true}
 end tell

Record Suite

This suite was added in version 1.9.3, and includes commands for manipulating AppleScript records.

You can create a new record, supplying the labels as strings, using the link values command like this:

 tell application "ASObjC Runner"
  link values {1, 2, 3} with labels {"theFirst", "theSecond", "theThird"}
  --> {theFirst:1, theThird:3, theSecond:2}
  link values {1, 2, 3} with labels {"theFirst", "theSecond", "theThird"} in record {theFirst:4, theFourth:4}
  --> {theFourth:4, theSecond:2, theFirst:1, theThird:3}
 end tell

If your data is a list of lists, you can convert it to a list of records using the link value lists command:

 tell application "ASObjC Runner"
  link value lists {{1, 2, 3}, {4, 5, 6}} with labels {"theFirst", "theSecond", "theThird"}
  --> {{theFirst:1, theThird:3, theSecond:2}, {theFirst:4, theThird:6, theSecond:5}}
 end tell

To get a list of all the labels as strings, use all labels of:

 tell application "ASObjC Runner"
  all labels of {theFirst:1, theSecond:2, theThird:3}
  --> {"theFirst", "theSecond", "theThird"}
  all labels of {theFirst:1, theSecond:2, theThird:1} for values {1}
  --> {"theFirst", "theThird"}
 end tell

Sometimes the labels in a record are reserved AppleScript terms, like name or text returned. In such cases, all labels of will return the four-letter code for the keyword, surrounded by the « and » symbols:

 tell application "ASObjC Runner"
  all labels of {text returned:"Hello", button returned:"OK"}
  --> {"«ttxt»", "«bhit»"}
 end tell

The remove entries labeled command lets you remove entries from a list of records:

 tell application "ASObjC Runner"
  remove entries labeled {"theSecond", "theThird"} in records {{theFirst:1, theSecond:2, theThird:3}, {theFirst:4, theSecond:5, theThird:6}}
  --> {{theFirst:1}, {theFirst:4}}
 end tell

The value for label command lets you extract the value for a particular label from all the records in a list:

 tell application "ASObjC Runner"
  value for label "theSecond" in records {{theFirst:1, theSecond:2, theThird:3}, {theFirst:4, theSecond:5, theThird:6}}
  --> {2, 5}
 end tell

The compare records command compares two records:

 tell application "ASObjC Runner"
  compare record {theFirst:1, theSecond:2, theThird:3} to record {theFirst:1, theSecond:5, theFourth:7} with exclusive only
  --> {{theThird:3}, {theFourth:7}}
  compare record {theFirst:1, theSecond:2, theThird:3} to record {theFirst:1, theSecond:5, theFourth:7}
  --> {{theThird:3, theSecond:2}, {theFourth:7, theSecond:5}}
 end tell

Version 1.9.10 introduced the merge records command, which offers several ways of merging a list of records.

XML Suite

This suite was added in version 1.9.5, and includes two commands: extract from XML, which lets you perform XPath queries on XML strings or files, and transform XML, which lets you perform XSLT transformations on XML.

The commands are based on Late Night Software's XSLT Tools.osax, which is no longer supported. They support a subset of the scripting addition's functionality, and use identical syntax. See http://www.latenightsw.com/freeware/XSLTTools/index.html.

Embedding ASObjC Runner in applets

You can embed a copy of ASObjC Runner in an applet you wish to run on a Mac that may not have ASObjC Runner installed on it. You should add the copy somewhere in the applet's Resources folder. You can see this folder by control-clicking on the applet in the Finder and choosing Show Package Contents.

You then use Standard Additions' path to resource command to get the path to the helper application. For convenience, you can store it in a property. Then when you want to address the application, you address it via the path within a using terms from block (it's probably easiest to wrap the whole script in the using terms from block).

When run for the first time, ASObjC Runner normally starts by showing its About window and by default does not display its menu. To avoid this window appearing with an embedded copy, you should rename the copy by adding either -N or -Y to the name (before the extension). With -N, no menu will appear in the menu bar, and with -Y it will; either way, no About window will appear the first time it is run. The embedded copy will also quit automatically within a minute of the last call to one of its commands, and will not automatically look for updates, if its name ends with -N or -Y.

Here is a simple example:

 using terms from application "ASObjC Runner" -- needed to compile script
 property runnerPath : ""
 -- get path to bundled copy, in this case directly in the Resources folder
 set runnerPath to (path to resource "ASObjC Runner-N.app") as text
 
 set theName to text returned of (display dialog "Enter your name:" default answer "")
 set theName to my makeCaps(theName)
 display dialog ("Your name in caps: " & theName) buttons {"OK"} default button "OK"
 -- we can quit manually, or rely on the auto-quit
 tell application runnerPath to quit
 
 on makeCaps(theText)
 tell application runnerPath
 return (modify string theText so it is caps)
 end tell
 end makeCaps
 end using terms from

It does not matter if multiple copies of ASObjC Runner are running, other than wasted memory. You could check for a running copy and use it if you would prefer; this would eliminate the short delay while ASObjC Runner launches.

OS Support

Barring bug fixes, version 1.9.11 will be the last version to support running in 32-bit mode. When released, version 2.0.0 and later will run only in 64-bit mode.

Changes since version 1.9.11

Version 1.9.12 is 64-bit only. The last 32-bit-capable version is 1.9.11, which is still available for download below.

A new await release of command will pause until the listed modifier keys are released, and will optionally flash the icon in the main menu bar.

Changes since version 1.9.9

The XML Suite is new.

Runs in either 64-bit or 32-bit mode under OS X 10.6. (v1.9.9 ran only in 32-bit mode under OS X 10.6.).

New 'merge records' command offers everal ways of merging records.

New 'elapsed time' property returns the elapsed time (in seconds) since the turn of the century. Designed to be used as a code timer.

Fixes crashing bug in 'modify list' when 'sublists' was wrongly set to true.

Fixed a potential crashing bug in 'modify list' command when the 'flattening' parameter is true. Also added 'fully flattening' parameter.

The result from 'split string ... with only first' has changed when the splitting string is not found. In such cases it now returns a list containing a single item, the full string. There is a also a new parameter, 'only last', for splitting only on the last occurrence.

The 'replace string' command also gets 'only first' and 'only last' parameters.

Fixed a crashing bug in the 'extract from XML' command. Also modified results and behavior of 'including output element' parameter when the query is for an attribute, to make it more useful.

The 'refine list' command has had it predicate string checking beefed up. It was previously fairly easy to pass an invalid predicate, resulting in the command not returning.

The 'mounted volumes' command now excludes /home and /net.

The 'about file' command has had nearly all its 10.8-deprecated Carbon code replaced with Cocoa code.

The underlying regular expression code has been updated for when running under OS X 10.7 or later. There should be no difference in behavior.

When using the 'look for' command with the 'invert' parameter set to true, if the pattern matches the full string, the result will be {"", ""}. The previous version incorrectly returned an empty list.

• Click here to return to the main ASObjC Runner page.

• Click here to read about using ASObjC Runner to run AppleScriptObjC code.

• Click here to download the application.

• Click here to download the last 32-bit-capable version of the application (v1.9.11).