Using the pessimistic version constraint operator with ruby gem versions

If you're a ruby developer, plugging a gem into a project is second nature. Most projects now use bundler to manage gem dependencies and versions, as it is so effective at doing so. If you've been doing this for long enough, then you will have come across the pessimistic version constraint operator, at least unknowingly.

You may know it as the spermy operator, or even_ twiddle waka_. You can see a whole conversation about the name in an issue on the rubygems Github.

Basically, it's this: ~>

What does it do? has a good description on it, so I'm not going to repeat too much of what is said there. But in summary, it allows you to specify a version for a gem plus a degree of flexibility.

Here's an example, from part of a Gemfile:

gem "nokogiri", "~> 1.6.0"

Here, although it looks like I've specified the exact version, the pessimistic operator means that the final number of the version can increase. Therefore, if version 1.6.4 of Nokogiri is released, then running bundle update nokogiri will allow it to be upgraded. However, if 1.7.0 is released, it will not update.

Why is this good?

If you don't specify versions for the gems in your project, then gems can upgrade to any version as it becomes available. Therefore, if a gem upgrades a major version, the API is likely to change and your project could break. It's therefore good practice to limit the maximum version to which a gem can upgrade. Having said that, you only really want to do this when your project is stable, and all the gems are working nicely together.

The answer, therefore, is to go through your Gemfile, collect the current versions for each gem and add them with the pessimistic constraint operator. However, that can be a bit of a hassle for a project with a large number of gems.

Introducing Pessimize

I've recently released a gem called pessimize, which does this for you. It's a command line tool that parses your Gemfile, collects all the versions of your gems and rewrites the Gemfile with the versions and ~> operator.

It's still in a sort of beta phase, so despite being heavily tested it backs up your Gemfile and Gemfile.lock, just in case. That means that you can revert back if something goes wrong (though you should really be using version control anyway).

It's simple to install through gem: gem install pessimize. You then get a command line script, pessimize. Just cd to any directory containing a Gemfile and run it, and it will generate a new Gemfile.

I really welcome pull requests, feature suggestions and feedback. I hope it saves you some time and encourages you to keep your gem dependencies in order!

← Previous post: Using project specific gemsets with Rails, RVM and Passenger Next post: Rails migrations, and a painful lesson →
comments powered by Disqus