Getting a new machine is always an exciting time. It's a chance to start fresh, free of the cruft that inevitably accumulates over years of use. When that opportunity recently presented itself to me, I decided to take full advantage of it by not copying over anything until I needed it, carefully evaluating each component along the way to make sure it was still the best choice.
The biggest change so far has been switching from compiling everything myself to using Homebrew. The other big change I decided to make, inspired by a recent talk at PDX.rb, was to switch from RVM to
RVM has served me well over the years as I've used it to develop dozens of applications and gems. I don't really have any complaints about it from a usability perspective, but I have noted a few annoyances of late.
RVM is a fairly heavyweight solution to the problem of needing to run multiple versions of Ruby. It overrides the
cdcommand, for instance, automatically evaluating the trusted
.rvmrcshell scripts scattered throughout your system as you navigate the directory hierarchy.
While it's nice to be able to specify an application's required Ruby version in its repository, it isn't quite as nice to do the same with the gemset name, which seems to be the modus operandi. Everyone has their own gemset naming and segregation schemes, and having to resort to hacks like
git update-index --assume-unchanged .rvmrcto override the settings in the repo's
.rvmrcis a pain.
~/.rvmdirectory can grow considerably in size over time as new Ruby versions are installed and the same gems are installed over and over again across gemsets. At last check, mine had grown to over 9 GB in size.
All of these are non-issues in the grand scheme of things, and, if anything, enumerating them just goes to show how great RVM is at doing what it's supposed to do.
After installing Homebrew, I used
brew install rbenv ruby-build to install
ruby-build. I opted to attempt to forego gemsets completely, despite the fact that there's an
rbenv-gemset plugin to provide that support for
While it has evolved a bit throughout the experiment, my current strategy is to configure Bundler with the following settings:
bundle config --global bin bin bundle config --global path .bundle
The first command configures Bundler to generate binstubs in the
bin directory of the application. This part isn't really new to me. I had already been using this setting under RVM, and have gotten into the habit of always running commands as
./bin/rspec instead of
bundle exec rspec.
The second tells Bundler to store the installed gems in the app's
.bundle directory. This effectively causes each project with a
Gemfile to be treated as an implicit gemset. To make sure this directory never finds its way into source control, I've added
.bundle to my global
~/.gitignore (you may need to run
git config --global core.excludesfile ~/.gitignore, too).
While this approach has worked remarkably well on the whole, there have been a few pain points during the transition.
I used to use RVM's
rmv wrappercommand to created isolated gemsets for global commands like
rbenv, I've had to resort to just using
gem installand letting them live in the global
GEM_HOME. In some ways, I actually prefer this to RVM's gem wrappers.
Because the gems are all tied to the bundle, the core Ruby commands like
irbdon't have access to them without using
bundle exec. Through a lot of experimentation, I've found that using the
rbenv-varsplugin and the following
~/.rbenv/varsfile to be the best solution:
Switching Ruby versions in a project may require the binary gems to be recompiled. This probably isn't really an issue in most day-to-day development, but it's something to be aware of.
There have also been a few beneficial side effects, too.
I appreciate not having to deal with
.rvmrcfiles any more. It's nice not seeing the trust prompts when changing directories, or having to resort to tricks like the
cd .. ; cd -) and running
rvm gemset listto make sure RVM is pointing to the right place.
.rbenv-versionfile is an effective replacement for the
.rvmrcfile's Ruby version specification, without the cruft of including a gemset name, too.
I like that all the code for an app, including its dependencies, is contained within the application root. This makes installing, moving, and removing applications simpler, in the same way that
.appbundles are convenient in OS X.
Having the gem source code contained within the project also means it can be more easily accessed. I can now use
.bundleas the path, where I previously had to use
rvm gemset dir.
In making this switch, I feel a bit like I've cheated on Wayne Seguin. He's one of the nicest guys you'll ever meet, and I truly respect the work that he does. I still think RVM is a valuable tool, and I hope it continues to be used by lots of developers.
My primary motivation for giving
rbenv a try was to see if I could get away with less. I'm not sure the experiment could be deemed a success on that metric alone. Each project requires a number of compromises, some of which have been detailed here. On the whole, though, I'm enjoying this
rbenv approach, and I don't feel a pressing need to switch back to RVM any time soon.