December 19th, 2008
I just recently built and installed three different Ruby versions (see Installing Ruby 1.8.6, 1.8.7 and 1.9 on Leopard). Following that I wanted to do some benchmark testing between 1.8 and 1.9 on a separate project so I began to use ZenTest's
multiruby. It worked great for the benchmarking and I started to think about how to use
multiruby as a way to manage and switch between Ruby installations. As I started looking into it I came across Dr Nic's Future proofing your Ruby code. Ruby 1.9.1 is coming post, which turned on the rest of the lights for me. The Dr Nic post does a nice job of describing how to use
multiruby including setting up specific Ruby versions, adding gem support and using it with sake tasks. I'll cover some of the same setup and usage information so that this post stands alone but I won't repeat it all so I recommend you read Dr Nic's post. In addition I'll provide information about how to overcome a RubyGems installation issue that I encountered and how to use the
multiruby Ruby installations as a way to dynamically switch between Ruby versions. I'll also discuss how the static build and install from source approach used in Installing Ruby 1.8.6, 1.8.7 and 1.9 on Leopard could be modified to be provide a non-
multiruby dependent way to do Ruby version switching. At the end of the post I'll mention using symlinks as an alternative and how that approach could be used with
multiruby is part of the popular ZenTest gem so it's likely you already have it. If you do have it but your revision is older than 3.11.0 you should update it, if it's not installed then it's available on rubyforge:
$ sudo gem install ZenTest
multiruby is run for the first time it sets up a hidden directory structure for Ruby versions in user home (
~/.multiruby) and downloads and installs the latest 1.8 and 1.9 releases of Ruby:
$ multiruby -e "p 1+1" ... Put other ruby tarballs in ~/.multiruby/versions to use them. ... VERSION = 1.8.7-p72 CMD = ~/.multiruby/install/1.8.7-p72/bin/ruby -e p 1+1 /Users/Rob/.multiruby/install/1.8.7-p72/bin/ruby: no such file to load -- ubygems (LoadError) RESULT = 256 VERSION = 1.9.0-5 CMD = ~/.multiruby/install/1.9.0-5/bin/ruby -e p 1+1 2 RESULT = 0 TOTAL RESULT = 1 failures out of 2 Passed: 1.9.0-5 Failed: 1.8.7-p72
I didn't show all of the output but left in the "
Put other ruby tarballs in ~/.multiruby/versions" line because it's worthy of note. If the installation worked then you'll see "
RESULT = 0" for each of the Ruby versions but in my case I had a "
no such file to load -- ubygems" error on the 1.8.7 version. This is a result of a conflict with the current Ruby installation. If you get the same error just temporarily unset the
RUBYOPT environment variable (
$ unset RUBYOPT ) and continue following these instructions. Updating RubyGems (coming right up) will correct the problem.
multiruby_setup is used to manage the installed ruby versions. The next step is to use the command to install the latest RubyGems update:
$ multiruby_setup update:rubygems
$ multiruby_setup" without any arguments will provide you with a usage list. One of the first things you'll want to know is how to control which versions of Ruby you use. The automatic version detection when
multiruby_setup is run the first time makes it easy to get started but in the case of 1.9 that means v1.9.0-5 is installed and it's more likely you'll want the latest 1.9.1 preview release. Dr Nic showed installing using subversion (
$ multiruby_setup mri:svn:tag:v1_9_1_preview2). So, just to be different, here's how to add preview2 from a tarball:
$ curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview2.tar.gz $ mv ruby-1.9.1-preview2.tar.gz ~/.multiruby/versions multiruby -e "p 1+1" $ multiruby -e "p 1+1"
Dr Nic also mentioned how to get a list of Ruby tagged releases with subversion (
$ svn list http://svn.ruby-lang.org/repos/ruby/tags). The equivalent for tarballs for 1.8 and 1.9 would be:
$ curl ftp://ftp.ruby-lang.org/pub/ruby/1.8/ $ curl ftp://ftp.ruby-lang.org/pub/ruby/1.9/
Now that we have the 1.9.1-preview2 release, here's the command to remove v1.9.0-5:
$ multiruby_setup rm:1.9.0-5
By default each version has it's own copy of RubyGems. If you want to leave it that way and install the same gems in all versions you can use Ruby's
-S option with multiruby. multiruby also looks for the VERSIONS and EXCLUDED_VERSIONS environment variables with verions separated by a ":". For example, if we had three Ruby versions installed:
$ multiruby_setup list Known versions: 1.8.6-p287 1.8.7-p72 1.9.1-preview2
and wanted to install Rails in just the 1.8 versions we could use:
$ export VERSIONS=1.8.6-p287:1.8.7-p72 $ multiruby -S gem install rails
$ export EXCLUDED_VERSIONS=1.9.1-preview2 $ multiruby -S gem install rails
Allowing each version to have it's own copy of gems provides fine grained control. If you'd rather just have all versions share gems (1.8 & 1.9 will still be separate) that can be done too:
$ multiruby_setup rubygems:merge
Switching Between Ruby Versions
The gem install example shows how
multiruby allows control of which versions it runs by setting environment variables but it adds output that you probably don't want when running a single version of Ruby. Dr Nic also points out how you can isolate and run a specific cucumber scenario against a specific ruby version by cutting and pasting the results of a multiruby run. It's simple to extend those concepts to allow any of the Ruby commands to change if we just modify the path. For example, to use the 1.9.1-preview2 version installed above:
$ export PATH=~/.multiruby/install/1.9.1-preview2/bin:$PATH ruby -v ruby 1.9.1 (2008-12-01 revision 20438) [i386-darwin9.5.0]
Having the path set is convenient since it also makes 1.9.1
irb, erb, gem and gem commands directly available.
Of course it's a pain to type the
export command each time and it would be nice to easily get back to the default Ruby installation. A simple solution is to add add aliases to your login initialization file. Depending on your shell this may be done differently but for my bash shell I added the following to the end of
22 23 24 25 26 27
# switch between ruby versions export ORIGPATH=$PATH alias mr186p287='export PATH=~/.multiruby/install/1.8.6-p287/bin:$ORIGPATH' alias mr187p72='export PATH=~/.multiruby/install/1.8.7-p72/bin:$ORIGPATH' alias mr191pre2='export PATH=~/.multiruby/install/1.9.1-preview2/bin:$ORIGPATH' alias mroff='export PATH=$ORIGPATH'
So switching to the latest 1.8.6 Ruby versions becomes as easy as:
$ mroff" reverts to the default install and "
$ alias" provides a reminder of what's available. I haven't done a lot with this switching method yet but so far it seems to work for me. If it continues to work well at some point I may even remove my
/usr/local Ruby installation and just add
mr186p287 to the end of my
.bash_login. Of course, I'll leave the Leopard 1.8.6 Ruby installation alone.
Other Ways to Switch Ruby Versions
I haven't tested this but the same alias-PATH method used above could be done without
multiruby by doing
/usr/local build and installs into a separate installation directory (instead of /usr/local/bin) and changing the configure portion of the build. For example, 1.9.1-preview2 could be build from source and aliased with:
$ sudo mkdir -p /usr/local/1.9.1-preview2 $ cd /usr/local/src $ curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview2.tar.gz $ tar xzvf ruby-1.9.1-preview2.tar.gz $ cd ruby-1.9.1-preview2 $ ./configure --prefix /usr/local/1.9.1-preview2 --enable-shared \ > --enable-pthread CFLAGS=-D_XOPEN_SOURCE=1 $ make $ sudo make install $ cd ..
22 23 24 25
# switch between ruby verisions export ORIGPATH=$PATH alias mr191pre2='export PATH=/usr/local/bin/1.9.1-preview2/bin:$ORIGPATH' alias mroff='export PATH=$ORIGPATH'
.bash_login. Again, I haven't tested this so there may be some tweaking to get the installation correct but it's the same principle as we used with the
multiruby solution. The upside is that you have complete control of builds and installations, but that seems minor there's no reason you can't do your own builds in the
~/.multiruby directories. On the downside you lose the sharing of Ruby versions with
multiruby and you lose
multiruby_setup's abilities to manage the versions as a group.
Another way to switch, and I what I thought I'd use prior to thinking about using PATH to switch between Ruby installations is a symlink system like Daniel Manages describes in his Install Multiple Versions of Ruby on Leopard. It's very similar to the
/usr/local method I just described but uses simlinks in
/usr/local/bin instead of adding to PATH. The symlinks could also be used with the
~/.multiruby/install versions to make to work with
multiruby as well.