Vanquish ghoulish bit rot in Ruby source code with Bundler, GitHub, and Ruby Tracker

UPDATE: I used htty as an example project in this post, but its use of Bundler has since changed. Because htty is a gem, its dependencies are now defined in htty.gemspec, along with all htty’s other RubyGems metadata.

Application projects (such as Rails applications) should use the techniques described in this post; RubyGems projects should not. To understand why, read Yehuda Katz’s post on this topic, “Clarifying the Roles of the .gemspec and Gemfile.”

I’ve made some amendments (in bold type) to this post.


Continuously upgrading your code’s dependencies can be a chore. But when you neglect the chore, it doesn’t take long for bit rot to start haunting you.

Today your code may run bug-free on Ruby interpreters and libraries. Tomorrow those other projects will advance and thereby invite poltergeists of incompatibility into your code. Before long your code won’t run at all on the versions everybody else will be using. There will be “fire and brimstone coming down from the skies, rivers and seas boiling, forty years of darkness, earthquakes, volcanoes, the dead rising from the grave, human sacrifice, dogs and cats living together — mass hysteria.” All right, all right — you get the point.

Bundler was created to exorcise the demons of dependencies in Ruby projects. Here I’ll explain a Bundler best practice for defining dependencies and a tip for upgrading dependencies over time.

By the way, I highly recommend getting comfortable with the combination of Bundler and RVM. It’ll help you wrangle combinations of Ruby interpreters and libraries with as much panache as Dr Venkman wrangled spooks, specters, and ghosts. You’ll say, “We came, we saw, we kicked its [stdout].”

Specify dependency versions in Gemfile

Gemfile is the file you use to describe your code’s dependencies to Bundler. Consider, for example, the Gemfile for htty (my console application for exploring web services and web sites). [Note that htty’s Gemfile no longer looks like this.]

A dependency can be tightened using a version spec expression (for example, gem 'rake', '~> 0.8', vs the looser gem 'rake'). But htty’s Gemfile contains no version specs.

Why is this?

First, version specs are already captured in Gemfile.lock. (Bundler generates Gemfile.lock from Gemfile.) There’s no need to duplicate this information. [Gemfile.lock is no longer under version control in the htty project.]

Second, omitting or loosening the version specs in your Gemfile means you can upgrade to a newer version of a dependency using a single Bundler command: bundle update name-of-gem. This command regenerates Gemfile.lock to reflect the newest available version of that dependency.

Note that when you first add a particular dependency to a Gemfile, you may wish to specify a version temporarily. For example, perhaps you want to use RSpec v2.0.0 in your project, even though the latest available version may be 2.1.0. You would:

  1. Cite an older version of RSpec in Gemfile: gem 'rspec', '2.0.0'.
  2. Update the bundle with the bundle command.
  3. Remove the RSpec version spec in Gemfile: gem 'rspec'.
  4. Commit the changes to Gemfile and Gemfile.lock.

The end result is exactly what you want. Your code depends on the desired, old version of RSpec, and your dependency configuration retains the convenience of a one-step upgrade when the need arises.

Keep up with evolving dependencies

How do you know when new versions of your dependencies are available? Must you periodically run bundle update to see what happens?

Enter Ruby Tracker, a useful addition to the GitHub open-source ecosystem. Ruby Tracker watches your project’s Gemfile.lock in your GitHub repository. It alerts you when new versions of the gems you depend on become available.

Gregg Pollack has a great little video explaining more about Ruby Tracker.

Create a Ruby Tracker account today and set it up to help you banish bit rot from your Ruby projects. end of article

Blog comments powered by Disqus
Follow Me on GitHub