Hacker News new | past | comments | ask | show | jobs | submit login
Tutorial: OS X automation with MacRuby and the Scripting Bridge (arstechnica.com)
76 points by shawndumas on Sept 27, 2011 | hide | past | favorite | 8 comments



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.


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].


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."


Interesting. What are the advantages of appscript over ScriptingBridge?


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.


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.


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.


You might be interested in seeing how http://code.google.com/p/csshx/ (Perl) manipulates Terminal windows.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: