Optimistic and Pessimistic Version Constraint

If your gem properly follows semantic versioning with its versioning scheme, then other Ruby developers can take advantage of this when choosing a version constraint to lock down your gem in their application.

Let’s say the following releases of a gem exist:

Version 2.1.0 — Baseline
Version 2.2.0 — Introduced some new (backward compatible) features.
Version 2.2.1 — Removed some bugs
Version 2.2.2 — Streamlined your code
Version 2.3.0 — More new features (but still backwards compatible).
Version 3.0.0 — Reworked the interface. Code written to version 2.x might not work.
Someone who wants to use your gem has determined that
  1. version 2.2.0 works with their software,
  2. but version 2.1.0 doesn’t have a feature they need.
  3. Adding a dependency in a gem (or a Gemfile from Bundler) might look like:

    # gemspec
    spec.add_runtime_dependency 'library',
      '>= 2.2.0'
    
    or
    # bundler
    gem 'library', '>= 2.2.0'
    
    This is an optimistic version constraint.

    It’s saying that all changes from 2.x on will work with my software, but for version 3.0.0 this may not be true.

  4. The alternative here is to use pessimistic version constraint.

    This explicitly excludes the version that might break your code.

    # gemspec
    spec.add_runtime_dependency 'library',
      ['>= 2.2.0', '< 3.0']
    
    or

    # bundler
    gem 'library', '>= 2.2.0', '< 3.0'
    
  5. RubyGems provides a shortcut for this, commonly known as the twiddle-wakka:

    # gemspec
    spec.add_runtime_dependency 'library',
      '~> 2.2'
    

    # bundler
    gem 'library', '~> 2.2'
    
    Notice that we dropped the PATCH level of the version number.

  6. Had we said ~> 2.2.0, that would have been equivalent to ['>= 2.2.0', '< 2.3.0'].

  7. If you want to allow use of newer backwards-compatible versions90.2 but need a specific bug fix you can use a compound requirement:

    # gemspec
    spec.add_runtime_dependency 'library', '~> 2.2', '>= 2.2.1'
    

    # bundler
    gem 'library', '~> 2.2', '>= 2.2.1'
    
  8. The important note to take home here is to be aware others will be using your gems, so guard yourself from potential bugs/failures in future releases by using ~> instead of >= if at all possible.

Casiano Rodriguez León 2015-01-07