-
Get a monthly update on best practices for delivering successful software.

Please continue reading after the next sentence.
I installed Snow Leopard a couple of weeks ago.
Wait -- don't stop reading. This isn't a post about how to install MySQL or a post about whether or not Snow Leopard is the Greatest Thing Ever. There are plenty of other places on the Internet where you can get that information.
I wanted to talk about two cool corners of the Ruby universe that I started using as a result of my Snow Leopard installation: MacRuby and RVM
One of the Ruby changes in Snow Leopard was an upgrade of the system Ruby version to 1.8.7. All fine, except that one of the projects I work on is on an older version of Rails that is not compatible. Clearly, I needed to get an 1.8.6 Ruby on my machine, ideally without messing up the system installation that other applications are using.
Enter Ruby Version Manager (RVM), a handy command line tool for installing and managing multiple Ruby interpreters on your system. In theory, usage is as simple as this:
$ gem install rvm $ rvm-install
At this point RVM asks you to make a slight change to your shell files. Then just this:
$ rvm use 1.8.6
"But you didn't have 1.8.6", I hear you cry. True. RVM will go out, download, compile, and install Ruby 1.8.6 to my local machine without interfering with anything else on the system (it installs in ~/.rvm). You can install Ruby 1.8.x, Ruby 1.9.x, Ruby Enterprise, JRuby, Rubinius, and (I think) MacRuby.
(Okay -- that's the ideal. In practice, it took a little bit of system tweaks and command line tweaks. Mike Gunderloy's Snow Leopard guide was helpful here. Although I've been able to get all the main Ruby versions to install, I'm still struggling some of the more esoteric version. Once installation is done, the command line interface is really good and things just work.)
Now, the Ruby in my shell is the new 1.8.6. But any other running terminal shells are unaffected -- especially helpful if you are working on multiple projects. Each Ruby maintains its own Gem listing, although there's work ongoing to make it easy to share gems.
To get back to the system Ruby, just
rvm use system
You can also specify any Ruby version as the default.
This is outstandingly cool, not just to solve my problem, but also as an easy way to create a harness to test your Ruby program or library against multiple Ruby setups. There are other useful features about setting different versions and managing shells, check it out.
Here's the thing. For the last several years I've had this script that communicates with iTunes via AppleScript, and creates a bunch of random playlists according to criteria that is a bit more complex that an iTunes smart playlist. For instance, it can create a playlist made up of two-song blocks by the same artist. Okay, it's wildly overdone, but I like it.
It broke in Snow Leopard. I don't know why. It seems like the Scripting Bridge framework occasionally decides to go out for a cup of coffee, and my script times out.
This seemed like as good a time as any to investigate MacRuby. MacRuby is an implementation of Ruby in Mac OS X Objective-C. Unlike a lot of hybrid language/vm tools, MacRuby gives you direct access to the native objects. So, if you ask for a string, you get an object that acts as both a Ruby string and a Cocoa NSString, responding to methods of either. MacRuby uses Ruby 1.9 key/value arguments to translate Objective-C method names.
[person name]; [person setName:name]; [person setFirstName:first lastName:last];
In Ruby (this example is from a tutorial on the MacRuby site)
person.name person.setName(name) person.setFirstName(first, lastName:last)
Unlike regular Ruby, the order of the keyword arguments must match the Cocoa method selector.
For most people, this allows writing Cocoa applications in Ruby, including integration with XCode and Interface Builder.
That's extremely useful, and I plan on trying it soon. For my purposes, the point is that it uses the Scripting Bridge directly, and I hoped that would allow it to bypass whatever weirdness was breaking my original script. (The original script was in Python, but I had a 75% functional Ruby version that I never actually built the I/O on, so it was largely a matter of learning the MacRuby way to communicate with iTunes.) Here's a sample, cobbled together from various parts of the script:
def itunes
@itunes ||= SBApplication.applicationWithBundleIdentifier(
"com.apple.itunes")
end
def library
@library ||= itunes.sources.objectWithName("Library")
end
def all_music
@all_music ||= library.userPlaylists.objectWithName("Music")
end
all_music.fileTracks.each_with_index do |track, index|
# stuff here
end
def create_itunes_playlist
playlist = itunes.classForScriptingClass(
"playlist").alloc.initWithProperties(
{'name' => name})
library.playlists.addObject(playlist)
playlist
end
#chosen_tracks are my object wrappers around Cocoa
#itunes_track is the actual cocoa object
playlist = create_itunes_playlist
chosen_tracks.each_with_index do |track, index|
track.itunes_track.duplicateTo(playlist)
end
Overall, everything works as advertised (it seems as though MacRuby is better able to deal with whatever happens to cause the Scripting Bridge to take a nap. I'm using the pre-release MacRuby 0.5, so there's the occasional feature glitch (gem installation is a little dicey, for example). But the MacRuby team is actively, even furiously, pushing forward, and this looks like it'll be very useful, very soon.
Related posts:
Topics: Ruby on Rails
Noel,
Thank you for using rvm! Please keep me posted with any feedback or questions you may have. I’ll be in #rvm on freenode IRC.
Also, FYI the “install on use” is now ‘opt-in’ as many people didn’t like that. You can simply set rvm_install_on_use=1 in your ~/.rvmrc and it should automatically try to install ruby versions that are not installed.
Enjoy!
~Wayne
Comment by Wayne E. Seguin, Friday, September 18, 2009 @ 11:48 am
Great post. A quick comment about MacRuby.
MacRuby 0.4 doesn’t run on SnowLeopard, you need to use MacRuby 0.5/trunk instead, nightly builds (pkg installers) are available at http://macruby.icoretech.org/
Also “Unlike regular Ruby, the order of the keyword arguments must match the Cocoa method selector.” isn’t entirely correct. MacRuby works just like C Ruby but it also supports Objective-C selector approach where foobar.foo(true bar:true, baz:true) calls a different method than foobar.foo(true baz:true, bar:true)
Basically, it’s an addendum to the language to support Cocoa. If you don’t use Cocoa, then you don’t need to worry about that.
Comment by Matt Aimonetti, Friday, September 18, 2009 @ 12:33 pm
[...] Corners of the Rubyverse: RVM and MacRuby | Pathfinder Software Development | Blogs [...]
Pingback by Ennuyer.net » Blog Archive » Rails Reading - Sept 21, 2009, Monday, September 21, 2009 @ 9:05 am
@Matt — sorry, that was unclear of me. I meant that the order of the keywords is only important when hitting Cocoa methods, but that’s still unusual from a Ruby perspective (I agree, though, that it’s a very clean way to go back and forth between Ruby and Obj-C syntax).
Comment by Noel Rappin, Monday, September 21, 2009 @ 12:43 pm