Syndication Icon
Published March 19, 2016 Updated October 21, 2021
Versionaire Icon


Git Badge
Gem Version
Alchemists Style Guide
Circle CI Status

Ruby doesn’t provide a primitive version type by default. Versionaire fills this gap by providing an immutable, thread-safe, and Semantic Version in order to use versions within your applications. This new version type behaves and feels a lot like other primitives (i.e. String, Array, Hash, etc) and can even be cast/converted from other primitives.


  • Provides Semantic Versioning.

  • Provides immutable, thread-safe version instances.

  • Converts (casts) from a String, Array, Hash, or Version to a Version.




  1. Ruby.


To install, run:

gem install versionaire

Add the following to your Gemfile:

gem "versionaire"



A new version can be initialized in a variety of ways:                            # "0.0.0"
Versionaire::Version[major: 1]                      # "1.0.0"
Versionaire::Version[major: 1, minor: 2]            # "1.2.0"
Versionaire::Version[major: 1, minor: 2, patch: 3]  # "1.2.3"


Value (#==)

Equality is deterimined by the state of the object. This means that a version is equal to another version as long as all of the values (i.e. state) are equal to each other. Example:

version_a = Versionaire::Version[major: 1]
version_b = Versionaire::Version[major: 2]
version_c = Versionaire::Version[major: 1]

version_a == version_a  # true
version_a == version_b  # false
version_a == version_c  # true

Knowning this, versions can be compared against one another too:

version_a > version_b                    # false
version_a < version_b                    # true
version_a.between? version_c, version_b  # true

Hash (#eql?)

Behaves exactly as #==.

Case (#===)

Behaves exactly as #==.

Identity (#equal?)

Works like any other standard Ruby object where an object is equal only to itself.

version_a = Versionaire::Version[major: 1]
version_b = Versionaire::Version[major: 2]
version_c = Versionaire::Version[major: 1]

version_a.equal? version_a  # true
version_a.equal? version_b  # false
version_a.equal? version_c  # false



Use the Versionaire::Version function to explicitly cast to a version:

version = Versionaire::Version[major: 1]

Versionaire::Version "1.0.0"
Versionaire::Version [1, 0, 0]
Versionaire::Version major: 1, minor: 0, patch: 0
Versionaire::Version version

Each of these conversions will result in a version object that represents “1.0.0”. When attempting to convert an unsupported type, a Versionaire::Errors::Cast exception will be thrown.


Building upon the examples shown above, there is an even more elegant solution where you can use this gem’s built-in refinement support:

using Versionaire::Cast

version = Versionaire::Version[major: 1]

Version "1.0.0"
Version [1, 0, 0]
Version major: 1, minor: 0, patch: 0
Version version

By adding using Versionaire::Cast to your implementation, this allows Versionaire to refine Kernel so you have a top-level Version conversion function much like Kernel’s native support for Integer, String, Array, Hash, etc. The benefit to this approach is it reduces the amount of typing, doesn’t pollute your entire object space like a monkey patch would, and provides a idiomatic approach to casting like any other primitive.


Implicit conversion to a String is supported:

"1.0.0".match Versionaire::Version[major: 1]  # <MatchData "1.0.0">


Explicit conversion to a String, Array, or Hash is supported:

version =

version.to_s  # "0.0.0"
version.to_a  # [0, 0, 0]
version.to_h  # {major: 0, minor: 0, patch: 0}


All versions are comparable which means any of the operators from the Comparable module will work. Example:

version_1 = Versionaire::Version "1.0.0"
version_2 = Versionaire::Version "2.0.0"

version_1 < version_2                    # true
version_1 <= version_2                   # true
version_1 == version_2                   # false (see Equality section above for details)
version_1 > version_2                    # false
version_1 >= version_2                   # false
version_1.between? version_1, version_2  # true
version_1.clamp version_1, version_2     # version_1 (added in Ruby 2.4.0)


Versions can be added, subtracted, sequentially increased, or sequentially decreased from each other.


Versions can be added together to produce a resulting version sum.

version_1 = Versionaire::Version[major: 1, minor: 2, patch: 3]
version_2 = Versionaire::Version[major: 2, minor: 5, patch: 7]
version_1 + version_2  # "3.7.10"


Versions can be substracted from each other as long as there isn’t a negative result.

version_1 = Versionaire::Version[major: 1, minor: 2, patch: 3]
version_2 = Versionaire::Version[major: 1, minor: 1, patch: 1]
version_1 - version_2  # "0.1.2"

version_1 = Versionaire::Version[major: 1]
version_2 = Versionaire::Version[major: 5]
version_1 - version_2  # Versionaire::Errors::NegativeNumber


Versions can be sequentially increased or given a specific version to jump to.

version = Versionaire::Version[major: 1, minor: 1, patch: 1]
version.up :major     # => "2.1.1"
version.up :major, 3  # => "4.1.1"
version.up :minor     # => "1.2.1"
version.up :minor, 3  # => "1.4.1"
version.up :patch     # => "1.1.2"
version.up :patch, 3  # => "1.1.4"


Versions can be sequentially decreased or given a specific version to jump to as long as the result is not negative.

version = Versionaire::Version[major: 5, minor: 5, patch: 5]
version.down :major     # => "4.5.5"
version.down :major, 3  # => "2.5.5"
version.down :minor     # => "5.4.5"
version.down :minor, 3  # => "5.2.5"
version.down :patch     # => "5.5.4"
version.down :patch, 3  # => "5.5.2"
version.down :major, 6  # => Versionaire::Errors::NegativeNumber


This project supports libraries which might desire native Version types. Each extension must be explicitly required in order to be used since they are optional by default. See below for details.


OptionParser is one of Ruby’s default gems which can accept additional types not native to Ruby by default. To extend OptionParser with the Version type, all you need to do is add these two lines to your implementation:

  1. require "versionaire/extensions/option_parser" - This will load dependencies and register the Version type with OptionParser.

  2. instance.on "--tag VERSION", Versionaire::Version - Specifying Versionaire::Version as the second argument will ensure OptionParser properly casts command line input as a Version type.

Here’s an example implementation that demonstrates full usage:

require "versionaire/extensions/option_parser"

options = {}

parser = do |instance|
  instance.on "--tag VERSION", Versionaire::Version, "Casts to version." do |value|
    options[:version] = value

parser.parse! %w[--tag 1.2.3]
puts options

The above will ensure --tag 1.2.3 is parsed as {:version⇒#<struct Versionaire::Version major=1, minor=2, patch=3>} within your options variable. Should OptionParser parse an invalid version, you’ll get a OptionParser::InvalidArgument instead.


To contribute, run:

git clone
cd versionaire

You can also use the IRB console for direct access to all objects:



To test, run:

bundle exec rake


Read Semantic Versioning for details. Briefly, it means:

  • Major (X.y.z) - Incremented for any backwards incompatible public API changes.

  • Minor (x.Y.z) - Incremented for new, backwards compatible, public API enhancements/fixes.

  • Patch (x.y.Z) - Incremented for small, backwards compatible, bug fixes.

Code of Conduct

Read Code of Conduct for details.


Read Contributions for details.


Read License for details.


Read Changes for details.


Engineered by Brooke Kuhlmann.