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
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 a
C++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
discrete Ruby development environments is not unlike juggling two
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 named
auto_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
interpreteris the name of a known interpreter and
gemsetis 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
- 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
bunzip2 utilities installed locally. In addition, your system
must have the
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
brew for Mac OS X. You must also have the
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
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.
Pick a Ruby, any Ruby
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.
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,
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 (email@example.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
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 /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
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
gem list. Switch back and run the command again.
Similar to the
gem command, the
also installs gems, albeit from a manifest named Gemfile. If you
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.
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
rvm gemset delete someset deletes the gemset
someset entirely. This too requires a prompt to
You can find a complete list of RVM commands by typing
rvm help, or refer to the documentation and tips found on the
Some additional tips
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—
Autoconf—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. The
get latestcommand refreshes your local code with the latest, stable version of the utility. If you want to try the bleeding edge of RVM, type
rvm 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 gemset
xyzif 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.
- 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.
- Follow developerWorks on Twitter.
- developerWorks blogs: Check out our blogs and get involved in the developerWorks community.
- Participate in the AIX and UNIX forums: