Easily manage your rubies with RVM, Bundler and Pik

Background

I’ve spent some time working on setting up an acceptance test framework using Cucumber and ruby under OSX on my ThoughtWorks MacBook Pro as my dev machine.

As a consultant, you can often work on a variety of projects, and these often have different ruby version requirements and use different ruby gems and dependencies. If you don’t use the help of a tool, it quickly becomes difficult to manage these various ruby versions, gems and dependencies.

RVM to the rescue

If you’re using Mac OSX and *-nix platforms, Ruby Version Manager, or RVM, is the tool for you:

“RVM is a command line tool which allows us to easily install, manage and work with multiple ruby environments from interpreters to sets of gems.”

At first, RVM was quite confusing to me, but over a short period of time I have grown to love it. It is *-nix only, but later I will explain what exists in the Windows world that is equivalent (Pik).

Reasons why RVM rocks

  • You can isolate and manage rubies and gemsets in those rubies
  • You associate these rubies and gemsets to projects – using .rvmrc and Gemfile files – so they consistently use the same ruby and gemset
  • It works with Bundler to fetch your ruby gems

RVM Explained in a Diagram

I decided to draw a diagram to explain this, using the really awesome Google docs drawings (goodbye Visio license costs).

RVMExplainedDiagram-AlisterScott
RVM Explained: click for larger view

.rvmrc files

You create one of these in your project root, which specifies which ruby version, and gemset, you want the project to use. When you “cd” into this directory, this is triggered by RVM to do the magic of switching your ruby version – so you’re system thinks you’re running a different version (the first time it asks you if you would like to trust it).

An example .rvmrc file


rvm_install_on_use_flag=1
rvm --create use jruby-1.5.3@celerity

An example message when cd’ing into this dictory


Using /Users/alisterscott/.rvm/gems/jruby-1.5.3 with gemset celerity

The really, really neat thing about this is, if you don’t have that version of ruby, or JRuby, installed then it will automatically fetch it and install it. Neat!

Managing your gems within RVM using Bundler

The second component of RVM that is very neat is gemsets.

A gemset is a collection of gems, that lives in a container that is associated with a version of ruby you have created in RVM: so you can have the same ruby version with various collections or groupings of gems.

Bundler (a gem itself) is used to collect your gems from your specified source – usually rubygems.org, but this can be a local gemserver if set up one in a corporate environment due to proxy issues.

As you’re running RVM with a ruby version and gemset already specified, when you run bundler (bundle install), these gems are inserted into your Gemset container. If you then switch RVMs or gemsets, you would simply rerun “bundle install” to insert the same gems into the different container. This is essentially what happens the first time you run your project on a server, the RVM or the Gemset won’t exist, so you create a script to switch to your correct rvm (using the .rvmrc file), install the bundler gem (because you need this to get the gem bundle), then run a bundle install.

Using RVM and Bundler to bootstrap configuration for running Cucumber features under C.I.

Use can RVM and Bundler to ensure your continous integration server runs your cucumber features correctly. An example shell script to do this on a unix box would be:


rvm rvmrc trust
cd features
cd .. # hack to load RVMRC
set -e
gem install bundler --no-rdoc --no-ri
bundle install
cucumber -p ci

A typical Gemfile


source "http://rubygems.org"
gem "cucumber", "0.10.0"
gem "prawn", "0.8.4"
gem "watir-webdriver", "0.1.8"
gem "celerity", "0.8.7"

I find it is best to specify explicit versions of gems in the GemFile, so you don’t have unexpected  consequences of automatically updating to a newer version of a gem without you knowing.

Gemfile.lock file

When you run bundle install for the first time, a Gemfile.lock directory is created. This contains the entire set of gem dependencies and their known versions that aren’t explicitly specified in your Gemfile (dependencies of your dependencies). This file is important as without it, when you run bundle install, bundler will look for fresh gem depencies, and these could change which could cause all kinds of versioning weirdness. This is why I would encourage people to store this file under version control.

Ruby Versioning on Windows: use Pik

When researching RVM for windows, I came across Pik, a similar concept, but with a little less finesse. Pik lets you have multiple ruby installs on your windows machine, and quickly switch between, or pik, which one you want to use.


C:\>pik switch 191 p129
   == Switching to ruby 1.9.1p129 (2009-05-12 revision 23412) [i386-mingw32] ==

It’s not as cool in the sense it doesn’t get and install your rubies for you, and there doesn’t seem to be same gemset concept, but fortunately Bundler still works the same, and can read your Gemfile.

So the get your ruby environment running on Windows, you could do something like

  1. pik switch 1.8.7
  2. gem install bundler
  3. bundle install

Not quite as neat as RVM, but still pretty neat.

A final note: running Cucumber under JRuby on Windows using Pik

To get coloured output (or non-weird looking output) for Cucumber on Windows under JRuby, you need to use Wac.

  • Download wac and put it on your path (I usually create a c:\bin directory and put this on my path, and put things it in)
  • Run “cucumber | wac” to see proper Cucumber output

Summary

  • RVM is a super neat tool that makes managing multiple ruby versions and gemsets a breeze.
  • There are so many useful scenarios for it, it is hard to describe here, but they include testing, continuous integration and deployment.
  • I find checking in the .rvmrc, Gemfile and Gemfile.lock files into your project ensures consistent reproducible ruby environments across multiple machines.

10 thoughts on “Easily manage your rubies with RVM, Bundler and Pik

  1. I asked you about this Wac library for Windows color support when using Cucumber in Twitter too, but i guess this tweet was unnoticed. My question was, doesn’t ANSICON [1] work with JRuby on Windows? It should work though. I cannot try currently.

    This Wac thing seems to be pretty outdated stuff and currently Cucumber and RSpec both need ANSICON to show colors in Windows on MRI. This could be different on JRuby of course.

    [1] http://adoxa.110mb.com/ansicon/

  2. Hi Alister,

    I am very new to Watir. Iam currently using Watir 1.7.1, Ruby 1.9.2 on windows. Since Ruby 1.8.7 environment is recommended I want to install 1.8.7
    and manage multiple versions of Ruby.From the above info I understand that by installing “Pik” I can switch between versions. So before running my scripts,
    I need to go to command prompt and do “C:\>pik switch 187 p129″.

    As I have installed 1.9.2 my folder structure looks something like this “C:\Ruby192\ruby\lib\gems\lib\”. All the gem files i.e. watir 1.7.1, firewatir 1.7.1 etc.
    are in this folder. If i install 1.8.7 i install only ruby but not gem files.

    Do I need to update or install gems after installing 1.8.7 because the path I would be using for 1.8.7 is different and gem files are not in this particular
    path.

    Please suggest,
    Thanks, ajazz.

    • Yes, you will need to install the gems into each and every ruby version you are using.
      You can use Bundler to make this repeatable.

      • Hi Alister,

        In my another system I use Ruby 1.8.7 and Watir 1.8.1.I installed 0.2.8 version of pik. After installing pik from Command Prompt I created a folder “C:\bin”
        and installed pik in the path “C:\bin” with the command “pik_install C:\bin”.
        Then I installed Ruby 1.9.2. After installing, I add this version to ‘pik’ with ‘pik add 1.9.2′
        I switch to 1.9.2 with the command ‘pik switch 192′. I am able to switch to the installed version..

        But when I open a new command prompt window and try to find out the ruby version it is showing the version as 1.8.7

        In the First Command Prompt window where I use the switch command, I get the ruby version as 1.9.2 and the second command prompt window gives 1.8.7.
        Also when I do ‘pik lists’ command, 2 versions are displayed.

        I have set the path like this in the Environment Variables

        PATH=C:\Ruby187\bin;C:\bin;C:\Ruby192\bin

        Is it the problem with the path or am i missing some thing.

        Thanks,
        ajazz.

        • I don’t believe pik updates the ruby version ruby reports back.
          Best to let pik tell you the ruby version.

        • You don’t have to modify the PATH manually at all. Pik does that for you. Maybe that even creates problems for you you’re seeing. This is my output for example:

          C:\Users\jarmo>pik sw 187

          C:\Users\jarmo>ruby -v
          ruby 1.8.7 (2010-08-16 patchlevel 302) [i386-mingw32]

          C:\Users\jarmo>pik sw 192

          C:\Users\jarmo>ruby -v
          ruby 1.9.2p136 (2010-12-25) [i386-mingw32]

    • You don’t have to specify patchlevel if you have only one Ruby 1.8.7. You can switch to it like this instead:
      pik sw 187

      And you can sync gems with 1.9.2 like this when under 1.8.7:
      pik gemsync 192

      • Iam exactly following the way mentioned above.Pik is able to switch the versions.

        I run the script by switching the version from 187 to 192, but script is taking “C:\Ruby187\bin\Ruby.exe” interpreter instead of running with “C:\Ruby192\bin\Ruby.exe”. This should not be the case.

        Do you think Iam missing something.

        The alternative I found for switching versions is When I want to use 192 Version, I mention the path of 192 in ‘PATH’ Environment Variable and vice versa.

Comments are closed.