Speaking UNIX, Part 14: Manage Ruby and gems with RVM

Get to know the Ruby Version Manager

Need to re-create another Ruby coder's development environment? Long to experiment with the latest version of JRuby? Want to isolate your work to a specific set of gems? You can do all that and more with the handy and clever Ruby Version Manager.

Share:

Martin Streicher (martin.streicher@locomotivellc.com), Conductor, Locomotive

Photo of Martin StreicherMartin 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.



23 July 2012

Also available in Chinese Portuguese

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 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 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_store associated with JRuby and a wholly different gemset named auto_parts_store associated 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, where interpreter is the name of a known interpreter and gemset is the name of an existing gemset. For example, 1.8.7p302@acme refers 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.


Getting started

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.


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.

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.


Managing 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.


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—Readline, IConv, zLib, OpenSSL, and 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 latest command. The get latest command 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 head to 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 --create command creates the gemset xyz if 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@health in 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.

Resources

Learn

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

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into AIX and Unix on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=AIX and UNIX, Open source
ArticleID=826748
ArticleTitle=Speaking UNIX, Part 14: Manage Ruby and gems with RVM
publish-date=07232012