Testing On Different Ruby Versions / Interpreters with rvm
I’ve been playing with a relatively new tool called rvm lately, and I’m loving it. rvm stands for Ruby Version Manager, and it does an exellent job at allowing different rubies to coexist. I currently have 7 versions installed on my machine:
ruby 1.8.6 ruby 1.8.7 patchlevel 72 (my system's default) ruby 1.8.7 patchlevel 174 ruby 1.9.1 ruby 1.9.2 preview1 jruby 1.3.1 rubinius 0.11.0
rvm makes it ridiculously easy to manage them.
Installing
Let’s start by installing rvm
$ gem install rvm $ rvm-install
and follow the instructions rvm-install gives you. Next, let’s install ruby1.9 (v1.9.1 by default).
$ rvm install 1.9
That’s it! rvm fetches the source, compiles the interpreter, and installs it in its own sandbox in ~/.rvm
For moar awesomes, you can install some non-MRI/YARV interpreters.
$ rvm install jruby $ rvm install rubinius
Switching between versions
$ rvm use 1.9 $ ruby -v ruby 1.9.1p243 (2009-07-16 revision 24175) [i686-linux] $ which ruby /home/mynyml/.rvm/ruby-1.9.1-p243/bin/ruby $ rvm use system #revert to using your system's ruby $ ruby -v ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux] $ which ruby /usr/bin/ruby
This speaks for itself, I believe.
Gems
Because each new version lives in its own sandbox, it starts off almost gemless (rvm pre-installs RubyGems and rake). You can install gems just as you normally would.
$ rvm use 1.9 $ gem install mynyml-every #don't use sudo $ rvm gemdir /home/mynyml/.rvm/gems/ruby/1.9.1 $ gem list *** LOCAL GEMS *** mynyml-every (1.0) rake (0.8.7)
Cross Version Testing
Here’s a rake task that will allow you to run your app’s tests across multiple ruby versions (provided you defined your own test task separately)
namespace(:test) do
desc "Run tests on multiple ruby versions"
task(:portability) do
versions = %w( 1.8.6 1.8.7 1.9 jruby rubinius )
versions.each do |version|
system <<-BASH
bash -c 'source ~/.rvm/scripts/rvm;
rvm use #{version};
echo "-------- `ruby -v` ---------\n";
rake -s test'
BASH
end
end
end
And run with:
$ rake -s test:portability
The reason the task looks hackish is because rvm isn’t a script, but a bash function. This function is loaded automatically when you open up a new shell because of the source line rvm-install added to your .bashrc file, but .bashrc itself isn’t loaded when you use #system. So the rake task first sources that function, and then runs everything else within the same session so that it uses its environment.
[update] As Wayne pointed out in the comments, there is a new rvm idiom that can be used to achieve this:
rvm 1.8.6,1.8.7,1.9,jruby,rubinius rake -s test
The rvm docs have also been updated to include this info.
Links
rvm’s official website has pretty good docs. You can also get a fairly good summary of functionality with
$ rvm help
source: http://github.com/wayneeseguin/rvm/
site/docs: http://rvm.beginrescueend.com/
tracker: https://www.pivotaltracker.com/projects/26822
group: http://groups.google.com/group/rubyversionmanager/
September 28th, 2009 at 11:42
Martin,
Awesome writeup, thank you. I would also like to point out some relatively new features of rvm for use with testing & benchmarking.
Running rake tasks across multiple versions is easy:
http://rvm.beginrescueend.com/rake/
Similarly for benchmarking code:
http://rvm.beginrescueend.com/benchmark/
One of the most useful not yet documented feature of rvm is:
$ rvm 1.8.7,1.9.1,jruby –json rake spec
This will run ‘rake spec’ against the three selected rubies and display a json formatted summary at the end. You can also use –yaml for a yaml formatted summary. This should be available and functioning in rvm >= 0.0.49.
~Wayne
September 28th, 2009 at 12:41
Thanks for the update, Wayne.
I didn’t know about the new “rvm v1,v2,… cmd” idiom. Really is much simpler, and certainly more elegant! I’ll update the post.