
Tutorial: OS X automation with MacRuby and the Scripting Bridge - shawndumas
http://arstechnica.com/apple/guides/2011/09/tutorial-os-x-automation-with-macruby-and-the-scripting-bridge.ars
======
js2
_As you can see from the example, we use Ruby's standard find, find_all, sort,
and map array methods. Chaining together Ruby blocks in this manner can be a
really convenient and syntactically expressive way to dig into the contents of
Scripting Bridge data structures_

I think that doing it that way sends many more apple events (and is thus much
slower) than needed. Here's two examples in Python. The first is similar to
the example ruby code in the article:

    
    
      from ScriptingBridge import SBApplication, NSPredicate
    
      iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
    
      library = [s for s in iTunes.sources() if s.name() == "Library"][0]
      playlist = [p for p in library.playlists() if p.name() == "Top 25 Most Played"][0]
      tracks = [t for t in playlist.tracks() if t.rating() > 3]
      
      favsongs = ["<li>%s - %s (%s)<li>" % (t.artist(), t.name(), t.playedCount())
                  for t in sorted(tracks, key=lambda t:t.playedCount())]
      
      print '\n'.join(favsongs)
    

The problem with this code is that we first ask iTunes for all its sources,
then filter those in Python. Next we ask the library source for all its
playlists, and again filter in Python. Etc.

Instead, we can rely on so-called lazy evaluation and send a single apple
event like so:

    
    
      library = iTunes.sources().objectWithName_("Library")
      playlist = library.playlists().objectWithName_("Top 25 Most Played")
      tracks = playlist.tracks().filteredArrayUsingPredicate_(
        NSPredicate.predicateWithFormat_("rating > 3"))
    

See the Apple Scripting Bridge documentation for more info.

------
georgecalm
For those who are interested, the tutorial is doable in Python too. One thing
to watch out for is that things that appear as properties are at times
functions; so safari.windows [rb] turns to safari.windows() [py] and
"window.currentTab.name" [rb] turns to "window.currentTab().name() [py].

------
js2
See also <http://appscript.sourceforge.net/>

"Appscript is a high-level, user-friendly Apple event bridge that allows you
to control scriptable Mac OS X applications from Python, Ruby and
Objective-C."

~~~
georgecalm
Interesting. What are the advantages of appscript over ScriptingBridge?

~~~
js2
The appscript documentation is excellent and I find its syntax (at least in
the Python case) a bit more "natural" than ScriptingBridge.

However, it does have to be installed separately. ScriptingBridge OTOH comes
installed with OS X.

------
JoelMcCracken
While OS X is great, it is slightly less hackable than I would like. MacRuby
is a great way to fix this. I have slowly been piecing together various
MacRuby scripts that do this sort of thing, and hopefully will someday be
releasing it. The goal is to create an emacs-like system (tiling window
manager, I mean) out of the entire OS. I entirely expect it to be somewhat
ugly, but workable.

~~~
albertzeyer
OSX is quite hackable. Check out these projects:

* <https://github.com/albertz/simbl>

* <https://github.com/albertz/FScriptAnywhereSIMBL>

* <https://github.com/albertz/Pyjector>

* <https://github.com/albertz/ChromeWebApps>

I have them running and they just inject to all running application and it is
pretty easy to make it all stable and just working fine because of Cocoa and
ObjC.

