As all Ruby developers will know, dependency management and isolation in projects is paramount. Example, project ‘A’ is based on a Ruby 1.9.2 and has a version of a gem that only works with 1.9.2 whereas project ‘B’ is a bleeding edge Ruby 2.0.1 application that only works with a few custom gems that you have created.
Until recently I was using rbenv
which worked great however it was incredibly slow at times - especially after I
had accumulated 12 or so different versions that I used at one point or another.
After drilling into the rbenv source code, it became obvious that the shim
inside of my .zshrc
file that rbenv required (eval "$(rbenv init -)"
) was
actually doing a rehash of all the Rubies everytime a new terminal instance was
started which would explain the ~1 sec additional load time when starting up.
It can be avoided by passing the --no-rehash
parameter however I also
didn’t want to start remembering to rehash everytime I made an update.a
After this digging I decided it was time to re-evaluate rbenv and check to see if there were any better solutions that had popped up which I had missed. Not long into the search I stumbled upon a little project called chruby.
chruby has a lot of cool features and all in ~90 lines of code!
- Updates
$PATH
. - Correctly sets
$GEM_HOME
and$GEM_PATH
. - Users: gems are installed into
~/.gem/$ruby/$version
. - Root: gems are installed directly into /path/to/$ruby/$gemdir.
- Additionally sets
$RUBY_ROOT
,$RUBY_ENGINE
,$RUBY_VERSION
and$GEM_ROOT
. - Calls
hash -r
to clear the command-lookup hash-table. - Fuzzy matching of Rubies by name.
- Defaults to the system Ruby.
- Optionally supports auto-switching and the .ruby-version file.
- Supports
bash
andzsh
. - Does not hook cd.
- Does not install executable shims.
- Does not require Rubies be installed into your home directory.
- Does not automatically switch Rubies by default.
- Does not require write-access to the Ruby directory in order to install gems.
Ok, cool. So now what? I started by removing all traces of rbenv (including the
Ruby binaries as I wanted to start completely fresh). To install chruby, I used
homebrew so it was as easy as brew install chruby
however it is available from
the source as well as a
setup script
if you are looking to get up and running quickly.
After that completes, you then need a way of installing additional Rubies. My
pick was to use ruby-install due
to it being simple and the easiest to get going with - there are other options
such as ruby-build that will also
work. Now that you have chruby installed and at least one of the many Rubies
available, it is time to tell your shell that it needs to start using it. Add
the following line to your .bashrc
or .zshrc
.
source /usr/local/share/chruby/chruby.sh
Additionally, chruby also supports auto switching based on a .ruby-version
file that is located in the current or parent directory. Even though it doesn’t
ship with it out of the box, it is also easy to enable. Just add the following
line to your .bashrc
or .zshrc
below the previous declared chruby line.
source /usr/local/share/chruby/auto.sh
Excellent! Now to set a system wide default so we can get off 1.8.7. There are a
couple of ways mentioned in the documentation on how to achieve this but I opted
to use the .ruby-version
file in my home directory as it was simple and I can
add it to my dotfiles under version control ;) .
echo "ruby-1.9" > ~/.ruby-version
Restart your shell and bam, chruby. You can see what Rubies are available by
running chruby
.
$ chruby
ruby-1.9.3-p392
jruby-1.7.0
rubinius-2.0.0-rc1
And manually switching can be done using chruby <version>
.
$ chruby
ruby-1.9.3-p392
jruby-1.7.0
rubinius-2.0.0-rc1
$ chruby ruby-1.9
$ chruby
* ruby-1.9.3-p392
jruby-1.7.0
rubinius-2.0.0-rc1
If you are migrating from another tool such as rbenv and don’t want to remove
all your existing Rubies, you can just point $RUBIES
to wherever you had them
previously installed by defining it in your .bashrc
or .zshrc
. E.g.
RUBIES=(
~/.rbenv/versions/*
/opt/jruby-1.7.0
$HOME/src/rubinius
)