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).
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.
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.
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
- pik switch 1.8.7
- gem install bundler
- 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
- 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.