Although Internet Relay Chat, forums, and revision control tools such as Git and Github make distributed development a snap, reproducing another developer's environment can be quite maddening. Propping up an existing body of code on a new development machine requires matching with at least some and potentially all of the original coder's stack, or many prerequisite software components that power the application. A stack may demand a type of operating system (say, UNIX®, Linux®, Mac OS, or Windows®); a specific operating system version (Ubuntu 10 or 11? Mac OS X 10.6 Snow Leopard or 10.7 Lion?); a minimum collection of built-in and supplemental system libraries and header files; a supporting cast of daemons and services (MySQL or PostgreSQL?); and, of course, any number of language-specific resources, from the compiler to a specific patch level of supporting open source code.
In the worst case, a piece of code is locked or dependent on a specific revision of each layer of the stack—perhaps even specific hardware. More ideally, standards and abstractions found up and down the stack facilitate portability. Portable Operating System Interface (POSIX) compliance is an example of a helpful standard: Otherwise differing systems that support the POSIX standards provide the same software interfaces and yield the same results. Interpreted languages such as Ruby are capable abstractions, because compilation is unnecessary and the code can (conceivably) run on any platform that offers an interpreter.
That said, even the application code written in interpreted languages, such as Perl, PHP, and Ruby require some adaptation to a new machine. In fact, Ruby oftentimes requires a good deal of setup, largely because Ruby is constantly and quickly evolving and is being pushed into more and varied computing environments. To wit, at the time of writing, there are two popular versions of the language in use, at least five Ruby interpreters based on three different computer languages, and several versions of each of those interpreters, not to mention tens of thousands of third-party libraries:
- Ruby version 1.8 is still in use, while Ruby version 1.9 is preferred in more recent coding efforts.
- The universe of Ruby interpreters includes Matz's Ruby Interpreter
(MRI—written in
C, named after the creator of Ruby, a Japanese computer scientist Yukihiro Matz Matsumoto); JRuby (written in the Java™ language and powered by a Java Virtual Machine [JVM]); Rubinius (written in Ruby, running atop aC++bytecode virtual machine [VM]); Ruby Enterprise Edition ([REE] a fork of the Ruby code and enhanced to boost the performance and lower the memory consumption); and MagLev (a fast and stable 64-bit implementation of Ruby based on VMware's GemStone/S 3.1 VM). (See Resources for links.) All the interpreters are open source. Each interpreter has its advantages, and the type of solution to use depends on the application and the preferences of the developer. - According to RubyGems.org, the official repository of contributed Ruby code, 41,780 gem instances are now available.
Confounding further, not all Ruby interpreters are interchangeable. While most code transfers
between implementations happen without any issues, there is no guarantee (in all cases) that one
interpreter will produce identical results to another. Given so much variety and a need to
compare results, Ruby developers need ready access to multiple stacks—just similar to
the developers coding in C—yet maintaining discrete
Ruby development environments is not unlike juggling two different C
compilers on your computer. Shell environment variables, including PATH, GEM_PATH, and
GEM_HOME help to segment one from another, but consistent, clear, and correct delineation
between one stack and a second requires a good deal of work and stringent discipline.
Now, Ruby developers have an almost magical alternative: the Ruby Version Manager (RVM), created by Wayne E. Seguin (see Resources for a link).
Introducing the Ruby Version Manager
RVM provides several indispensable features:
- RVM can currently build more than 35 implementations. With one command, RVM downloads, builds, and installs any of those Ruby interpreters.
- It creates and manages any number of Ruby environments, where each environment proffers an individual Ruby interpreter. Hence, one project can use JRuby and another project, being developed on the exact same computer, can specify the latest MRI.
- Further, each environment can have any number of discrete gem collections.
RVM aptly calls each assembly a gemset. You can have a gemset
named
auto_parts_storeassociated with JRuby and a wholly different gemset namedauto_parts_storeassociated with the MRI version 1.9.3. Each gemset must have a unique name in the context of an interpreter. - The combination of an interpreter and a gemset (providing the engine to run
the Ruby code and the body of the library code) is easily referred to with the notation
interpreter@gemset, whereinterpreteris the name of a known interpreter andgemsetis the name of an existing gemset. For example,1.8.7p302@acmerefers to the Ruby MRI patch level 302 for version 1.8.7 of the language and a collection of gems for the Acme website. The name of a gemset is arbitrary. The names of the individual interpreters are provided by RVM. - Switching between the environments is a snap. You need to type the following command:
rvm interpreter@gemset. - Each environment is self-contained and siloed (typically) within your home directory. Indeed, the entire RVM system lives in your home directory, ensuring that another user cannot clobber or pollute what you have assembled, and similarly, you cannot pollute what other users have assembled. (You can also install RVM centrally, but it is an uncommon practice.)
- You can run your application's test suite against one, some, or all of your environments. Run MRI locally, but use REE on your server. Use RVM to test your code against both, before you push the revisions live.
RVM allows you to try combinations of code quickly so that you can keep your application stable and modern. If a new MRI is released, you can build it in RVM, create a new environment, run tests, and settle on the new MRI if all is well.
RVM is simple to install. All it requires is one command and a small change to your shell startup script.
However, RVM does have some prerequisites. Before you continue, check your system and
be sure that you have the bash, git,
tar, curl, gunzip,
and bunzip2 utilities installed locally. In addition, your
system must have the Readline, IConv,
zLib, OpenSSL, and
Autoconf packages to build the Ruby interpreters. You
must have the Bash shell to install RVM, but you can use RVM with the Z shell version
4.3.5 or higher after RVM is installed. git is required to
automatically update RVM, and this is explained shortly.
If your system lacks all the packages listed, you can quickly install them using a package
manager, such as Advanced Packaging Tool for various Linux distributions or
brew for Mac OS X. You must also have the GNU
C compiler to build applications.
After your system is ready, go to a shell prompt and type (or copy and paste) the command:
$ bash < <(curl http://rvm.beginrescueend.com/releases/rvm-install-head) |
Note: There is a space between the two less-than
(<) symbols. The special Bash syntax
<(...) runs the commands in parentheses and saves
the output in a temporary file. The first < is the
typical input redirection. Hence, the command runs bash
and provides the input from a temporary file created by curl.
Think of the sequence as running a shell script, albeit one stored on a remote
server.
Once your system is ready, go to a Shell prompt and type (or copy and paste) the command.
$ curl -L https://get.rvm.io | bash -s stable
The command uses git to clone and create a local instance
of RVM in your home directory. Look in $HOME/.rvm: The bin subdirectory contains
the rvm utility itself, while rubies is the eventual home
of your Ruby interpreters. You will find that RVM organizes the software that you amass in a
predictable hierarchy based on the interpreter type, version, and gemset.
After the installation script is complete, you must edit your shell's dot or startup files to load the RVM shell functions whenever a new shell starts. In general, the line:
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" |
. . . must be the last line in the dot file loaded whenever an interactive shell starts.
If you use bash, append the line to the end of
your $HOME/.bashrc file. To have the change take effect, you must launch a new
shell or type source $HOME/.bashrc to reload the file.
Now that RVM is installed, it's time to download, build, and install one or more Ruby
interpreters. There are many variations available, counting language versions, patch levels,
and underlying implementations. You can list all known variations
with the rvm list known command, as shown in
Listing 1.
Listing 1. Listing all known Ruby interpreter variations
$ rvm list known
# MRI Rubies
[ruby-]1.8.6[-p420]
[ruby-]1.8.6-head
[ruby-]1.8.7[-p352]
[ruby-]1.8.7-head
[ruby-]1.9.1-p378
[ruby-]1.9.1[-p431]
[ruby-]1.9.1-head
[ruby-]1.9.2-p180
[ruby-]1.9.2[-p290]
[ruby-]1.9.2-head
[ruby-]1.9.3-preview1
[ruby-]1.9.3-rc1
[ruby-]1.9.3[-p0]
[ruby-]1.9.3-head
ruby-head
# GoRuby
goruby
# JRuby
jruby-1.2.0
jruby-1.3.1
jruby-1.4.0
jruby-1.6.1
jruby-1.6.2
jruby-1.6.3
jruby-1.6.4
jruby[-1.6.5]
jruby-head
# Rubinius
rbx-1.0.1
rbx-1.1.1
rbx-1.2.3
rbx-1.2.4
rbx[-head]
rbx-2.0.0pre
# Ruby Enterprise Edition
ree-1.8.6
ree[-1.8.7][-2011.03]
ree-1.8.6-head
ree-1.8.7-head
# Kiji
kiji
# MagLev
maglev[-head]
maglev-1.0.0
# Mac OS X Snow Leopard Only
macruby[-0.10]
macruby-nightly
macruby-head
# IronRuby -- Not implemented yet.
ironruby-0.9.3
ironruby-1.0-rc2
ironruby-head
|
The patch level 352 MRI for Ruby 1.8.7 provides a good foundation for both Ruby and Rails development. Let us install it first.
Type rvm install and the name of the engine,
ruby-1.8.7-p352. You can also type
rvm install 1.8.7. Portions of the interpreter names that
appear in brackets ([]) are optional, so
rvm install 1.8.7 is the same as
rvm install ruby-1.8.7-p352. In general, if you simply
name a version, RVM installs the latest code for that version.
When you install an interpreter, RVM downloads and builds the code for you. Listing 2 shows the code.
Listing 2. Building the interpreter
$ rvm install 1.8.7 Installing Ruby from source to: /Users/strike/.rvm/rubies/ruby-1.8.7-p352, this may take a while depending on your cpu(s)... ruby-1.8.7-p352 - #fetching ruby-1.8.7-p352 - #downloading ruby-1.8.7-p352, this may take a while depending on your connection... ruby-1.8.7-p352 - #extracting ruby-1.8.7-p352 to /Users/strike/.rvm/src/ruby-1.8.7-p352 ruby-1.8.7-p352 - #extracted to /Users/strike/.rvm/src/ruby-1.8.7-p352 Applying patch 'stdout-rouge-fix' located at /Users/strike/.rvm/patches/ruby/1.8.7/stdout-rouge-fix.patch) ruby-1.8.7-p352 - #configuring ruby-1.8.7-p352 - #compiling ruby-1.8.7-p352 - #installing Retrieving rubygems-1.8.10 Extracting rubygems-1.8.10 ... Removing old Rubygems files... Installing rubygems-1.8.10 for ruby-1.8.7-p352 ... Installation of rubygems completed successfully. ruby-1.8.7-p352 - adjusting #shebangs for (gem irb erb ri rdoc testrb rake). ruby-1.8.7-p352 - #importing default gemsets (/Users/strike/.rvm/gemsets/) Install of ruby-1.8.7-p352 - #complete |
To switch to the 1.8.7 interpreter just installed, type rvm 1.8.7.
To list the specifics of your current environment, type rvm info.
Listing 3 shows the code.
Listing 3. Switching to the 1.8.7 interpreter
$ rvm 1.8.7
$ rvm info
rvm:
version: "rvm 1.10.0-pre by Wayne E. Seguin
(wayneeseguin@gmail.com) [https://rvm.beginrescueend.com/]"
ruby:
interpreter: "ruby"
version: "1.8.7"
date: "2011-06-30"
platform: "i686-darwin11.2.0"
patchlevel: "2011-06-30 patchlevel 352"
full_version: "ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-darwin11.2.0]"
homes:
gem: "/Users/strike/.rvm/gems/ruby-1.8.7-p352"
ruby: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352"
binaries:
ruby: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352/bin/ruby"
irb: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352/bin/irb"
gem: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352/bin/gem"
rake: "/Users/strike/.rvm/gems/ruby-1.8.7-p352/bin/rake"
environment:
PATH: "/Users/strike/.rvm/gems/ruby-1.8.7-p352/bin:
/Users/strike/.rvm/gems/ruby-1.8.7-p352@global/bin:
/Users/strike/.rvm/rubies/ruby-1.8.7-p352/bin:/Users/strike/.rvm/bin:
/Users/strike/.gem/ruby/1.8.7/bin:/Users/strike/.ruby_versions/ruby-1.8.7-p174/bin:
/Users/strike/bin/rds:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11/bin"
GEM_HOME: "/Users/strike/.rvm/gems/ruby-1.8.7-p352"
GEM_PATH: "/Users/strike/.rvm/gems/ruby-1.8.7-p352:
/Users/strike/.rvm/gems/ruby-1.8.7-p352@global"
MY_RUBY_HOME: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352"
IRBRC: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352/.irbrc"
RUBYOPT: ""
gemset: ""
|
The most important information is found in the interpreter,
version, patchlevel, and
gemset lines, which reflect the type, language version,
revision of the interpreter, and the current gemset, respectively. If you
change to a new environment, for example to ree@auto_parts_store, those
lines will change accordingly. Indeed, most of the information shown will change each
time you switch environments. Again, RVM automates the process of altering shell
settings and variables to create an island for each RVM environment. Notice that
PATH has been changed to point to the new Ruby. To confirm, type
which ruby.
$ which ruby /Users/strike/.rvm/rubies/ruby-1.8.7-p352/bin/ruby |
As you can see, the foremost Ruby executable in the path is the one just installed.
To install a different Ruby interpreter, run rvm install
again specifying a different name. Type rvm list at any time to discover the
rubies that you have installed locally.
$ rvm list jruby-1.6.4 [ x86_64 ] ree-1.8.7-2009.10 [ i686 ] ree-1.8.7-2010.02 [ i686 ] ruby-1.8.7-p334 [ i686 ] => ruby-1.8.7-p352 [ i686 ] ruby-1.9.2-p0 [ x86_64 ] ruby-1.9.2-p290 [ x86_64 ] |
The arrow in the output indicates the Ruby interpreter that is currently in use.
Similarly, if you want to know the names of all the gemsets defined in the current
environment, type rvm gemset list. Again, an arrow
indicates the current gemset in use.
$ rvm gemset list gemsets for ruby-1.8.7-p352 (found in /Users/strike/.rvm/gems/ruby-1.8.7-p352) brewster canvas-src global => miner moms tech |
Of these gemsets, the one named global is special. As
Wayne Seguin explains, "RVM provides a global gemset
per Ruby interpreter. Gems you install to the global gemset
for a given Ruby are available to all other gemsets you create in association with that
Ruby. This is a good way to allow all your projects to share the same installed gem for
a specific Ruby interpreter installation." Let us look at how to create, delete, expand,
and switch to different gemsets.
RVM allows you to switch from one interpreter to another. You can now develop a new code based on the features and syntax of Ruby version 1.9.2 in one directory and maintain an older 1.8.7 code base in another directory, all on the same computer. You can even run a single code base under any Ruby version of your choice.
The next step is to manage the library dependencies of projects using independent gemsets.
To demonstrate this, assume that directory web-1.8.7 contains a Rails application that is based on Rails 3.1 and Ruby 1.8.7, while directory daemon-1.9.2 is a system daemon written in Ruby, based on version 1.9.2. (You need not put the version number in the name of the directory; here, things are explicitly named to minimize confusion.) Give each code base its own gemset, and explore how to populate each.
To switch to 1.8.7, type rvm 1.8.7. Type
rvm gemset create web to create a new gemset named
web, as Listing 4 shows.
Listing 4. Creating and selecting a gemset
$ cd web-1.8.7 $ rvm 1.8.7 $ rvm gemset create web $ rvm gemset list brewster canvas-src global => miner moms tech web $ rvm gemset use web $ rvm gemset list brewster canvas-src global miner moms tech web => web $ rvm info ruby: interpreter: "ruby" version: "1.8.7" ... patchlevel: "2011-06-30 patchlevel 352" ... gemset: "web" |
rvm gemset create manufactures a new gemset but does not
make it the current, active gemset. Use rvm gemset use
to switch to a particular gemset. You can check or confirm your state at any time by using the
rvm info command.
After your new gemset is active, any command that installs the gems affects only that gemset.
For example, the familiar command gem install adds a
list of gems. When a gemset is active, the gems are not installed to the system gem
cache but to the gemset's own cache, as shown in Listing 5.
Listing 5. Installing gems into a gemset
$ rvm gemset use style --create
$ gem list
$ gem install rails
Fetching: multi_json-1.0.4.gem (100%)
Fetching: activesupport-3.1.3.gem (100%)
Fetching: builder-3.0.0.gem (100%)
Fetching: i18n-0.6.0.gem (100%)
Fetching: activemodel-3.1.3.gem (100%)
...
Successfully installed rails-3.1.3
29 gems installed
$ gem list
*** LOCAL GEMS ***
actionmailer (3.1.3)
actionpack (3.1.3)
activemodel (3.1.3)
activerecord (3.1.3)
activeresource (3.1.3)
activesupport (3.1.3)
arel (2.2.1)
builder (3.0.0)
bundler (1.0.21)
erubis (2.7.0)
hike (1.2.1)
i18n (0.6.0)
json (1.6.3)
mail (2.3.0)
mime-types (1.17.2)
multi_json (1.0.4)
polyglot (0.3.3)
rack (1.3.5)
rack-cache (1.1)
rack-mount (0.8.3)
rack-ssl (1.3.2)
rack-test (0.6.1)
rails (3.1.3)
railties (3.1.3)
rake (0.8.7)
rdoc (3.12)
sprockets (2.0.3)
thor (0.14.6)
tilt (1.3.3)
treetop (1.4.10)
tzinfo (0.3.31)
|
To verify that the gems are siloed in the gemset, switch to another gemset and rerun
gem list. Switch back and run the command again.
Similar to the gem command, the bundler command also installs
gems, albeit from a manifest named Gemfile. If you run bundler
in the context of a gemset, the gems are added solely to that collection. Combine
RVM and bundler to switch easily between one Rails project
and another.
If you need to re-create a gemset from scratch, you can erase all the contents in one
fell swoop with rvm gemset empty someset. Because
rvm empty is destructive and irreversible, RVM prompts
for confirmation. Type yes to proceed:
$ rvm gemset empty someset
WARN: Are you SURE you wish to remove the installed gems for
gemset 'ruby-1.8.7-p352@someset' (/Users/strike/.rvm/gems/ruby-1.8.7-p352@someset)?
(anything other than 'yes' will cancel) > yes
$ rvm gemset delete someset
WARN: Are you SURE you wish to remove the entire gemset
directory 'someset' (/Users/strike/.rvm/gems/ruby-1.8.7-p352@someset)?
(anything other than 'yes' will cancel) > yes
|
The line: rvm gemset delete someset deletes the gemset
someset entirely. This too requires a prompt
to proceed.
You can find a complete list of RVM commands by typing rvm help,
or refer to the documentation and tips found on the RVM website.
RVM is simple to master, but has a deep and broad feature set that turns many development tasks into quick work. Here is just a sample of some of the gems found in the utility.
- Ideally, your system has all the utilities and packages listed as prerequisites
before you try to build a Ruby. However, if you cannot install or build
any of those packages—say, because you do not have sufficient
privileges to customize your computer—RVM provides an alternative.
You can install each of the five libraries—
Readline,IConv,zLib,OpenSSL, andAutoconf—in your own $HOME/.rvm directory as a private copy and use RVM as usual. - RVM itself is revised often. You can automatically update your RVM software
by using the
rvm get latestcommand. Theget latestcommand refreshes your local code with the latest, stable version of the utility. If you want to try the bleeding edge of RVM, typervm get headto install the latest revision. - If you create gemsets often, you may prefer a shortcut to create and use
the gemset in one step. The
rvm gemset use xyz --createcommand creates the gemsetxyzif it does not exist and immediately switches to that gemset. - If you use a specific environment for one project, you can add a special dot
file to the root of the project to automatically switch to the environment
whenever you enter the project's directory. Simply create a .rvmrc file
and write the RVM command that you would typically use on the command line
to switch to the environment you want. For example, if you put
rvm ree@healthin the file, RVM automatically sets the correct interpreter and gemset when you change the directory to any folder in the project. - If you check your .rvmrc and Gemfile into source code control, the next developer to encounter your work can quickly regenerate all the requirements needed to continue development.
RVM is a Ruby developer's best friend
RVM is sure to become indispensable almost immediately. RVM can likely do away with VMs or small slices that you maintain as alternative or additional Ruby development environments. Better yet, as Ruby evolves, you can keep pace with RVM.
Learn
-
Read more about the creator of the Ruby language,
Japanese computer
scientist Yukihiro "Matz" Matsumoto.
-
Learn more about Ruby from its official website,
www.ruby-lang.org/en, and learn how
to code in Ruby from its official documentation.
-
AIX and UNIX developerWorks
zone: The IBM AIX® and UNIX zone provides a wealth of information relating to
all aspects of AIX systems administration and expanding your UNIX skills.
-
New to AIX and UNIX?
Visit the New to AIX and UNIX page to learn more.
-
Technology
bookstore: Browse the technology bookstore for books on this and other
technical topics.
Get products and technologies
-
You can download the RVM and read extensive documentation from its
project page.
-
Ruby runs in several different interpreters. JRuby runs
Ruby within a JVM; Rubinius converts Ruby into
bytecode with Ruby and executes applications within a
C++VM. And MagLev is based on VMware's GemStone/S 3.1 VM. -
Many developers and open source projects keep code under version control with
Git and
Github.
Discuss
-
Follow developerWorks on Twitter.
-
developerWorks blogs: Check out
our blogs and get involved in the developerWorks
community.
-
Participate in the AIX and UNIX forums:
- AIX forum
- AIX for Developers Forum
- Cluster Systems Management
- IBM Support Assistant
- Performance Tools
- More AIX and UNIX forums

Martin Streicher is a professional Ruby developer. He is the former Editor-in-Chief of Linux Magazine and a regular contributor to developerWorks. Martin holds a Masters of Science degree in Computer Science from the Purdue University and has programmed UNIX-like systems since 1986. He collects art and toys. You can read Martin's blog and contact him at martin.streicher@locomotivellc.com.



