Versioning your Ruby Library

Aaron Beckerman
January 21, 2014

Ruby is fortunate to have a large collection of third-party libraries - gems - and a typical Rails application uses dozens of them. As a result, whenever Rails developers update gems or investigate problems with them, they’re thinking about versions. If you’re going to share code with this community, how should you handle versions?

Say you have a Ruby library to share with the world. You noticed that programmers couldn’t figure out how to make the current time a parameter of their methods, so you helped them write unit tests by making yet another gem for globally mocking the current time (YAGFGMTCT). YAGFGMTCT will have versions: You’re going to fix bugs. You’re going to add new features - YAGFGMTCT really should offer a domain-specific language, after all.

How should you label these versions? Are cat species still cool? (“Fixed in YAGFGMTCT Caracal,” you note in the bug report.) They are not. This is not an exercise in marketing; you want version labels that communicate relevant technical information to the programmers that use your gem.

Versioning for Ruby and Rails

You want to be a good Rubyist and adhere to the community’s customs, so perhaps you should use the same scheme as Matz’s Ruby Interpreter, Ruby’s reference implementation. MRI has versions like 1.9.3-p484, and they indeed communicate information. The first number increments to signify a big change to the language; the second number increments to an odd number to signify an experimental version of the interpreter, although it doesn’t really mean that anymore…. Hmm. Perhaps, you think, this scheme doesn’t really apply to your gem. Even if it has an awesome DSL.

How about that most prominent of gems, Rails? Surely the Rails versioning policy is a good example to follow? Not really; Rails does its own thing.

Versioning for You

The Ruby community has a preferred system for gem versions, and that’s probably a better fit for you. Ruby itself doesn’t use it. Rails doesn’t use it. But you should use it - trust us.

It’s a three-number scheme, X.Y.Z. X is called the major number, Y is called the minor number, and Z is called the patch number. By changing the numbers according to certain rules, you communicate how much your gem’s API has changed.

  • If code written for the previous version won’t necessarily work with the new version, you increment the major number and zero the others. For example, say YAGFGMTCT 1.2.1 has a feature that causes time to go in reverse. You realise that was a mistake and decide to remove it. In this case, the new version number should be 2.0.0.

  • If code written for the previous version will still work, and you’ve added new features, you increment the minor number and zero the patch number. So if you add a method that lets the user specify a time with a natural-language string, like “4 November 2013”, and make no other changes, the version should go from 1.2.1 to 1.3.0.

  • If code written for the previous version will still work, but there are no new features, you increment the patch number. For example, if you fix a bug and add a section to the README file, the version should go from 1.2.1 to 1.2.2.

This system is formalised as Semantic Versioning, and it’s already very popular in the Ruby community. If you’re disciplined about using it for your own gem, your users will benefit.

  • At a glance, they’ll be able to make a rough guess at how much work they’ll need to do to upgrade.
  • If they’re making a gem that depends on yours, they’ll be able to specify version constraints with confidence.

The more standard this becomes, the more programmers can rely on it, and the more the gem ecosystem benefits.