Skip to content

Repository files navigation

Vers - Version Range Parser for Ruby

A Ruby library for parsing, comparing and sorting versions according to the VERS specification.

This gem provides tools for working with version ranges across different package managers, using a mathematical interval model internally and supporting the vers specification from the Package URL (PURL) project.

RubyGem VersionLicense: MIT

Available on RubyGems | API Documentation | GitHub Repository

Features

  • Universal version range parsing with support for 6 package ecosystems (npm, gem, pypi, maven, debian, rpm)
  • Mathematical interval model for precise set operations (union, intersection, complement)
  • VERS specification compliance with full support for the Package URL version range specification
  • Native syntax support - parse native package manager syntax (^1.2.3, ~>1.0, >=1.0,<2.0, [1.0,2.0))
  • Bidirectional conversion between native syntax and universal vers URI format
  • Semantic versioning features - version increment, constraint checking, prerelease handling
  • Comprehensive error handling with detailed parsing exceptions
  • 100% test coverage with 113 tests and 366 assertions

Installation

Add this line to your application's Gemfile:

gem'vers'

And then execute:

bundle install

Or install it yourself as:

gem install vers

Quick Start

require'vers'# Parse a vers URIrange=Vers.parse("vers:npm/>=1.2.3|<2.0.0")range.contains?("1.5.0")# => truerange.contains?("2.1.0")# => false# Parse native package manager syntaxnpm_range=Vers.parse_native("^1.2.3","npm")gem_range=Vers.parse_native("~> 1.0","gem")# Check version containmentVers.satisfies?("1.5.0",">=1.0.0,<2.0.0")# => true# Compare versionsVers.compare("1.2.3","1.2.4")# => -1# Version operationsversion=Vers::Version.new("1.2.3")version.increment_major# => #<Vers::Version "2.0.0">version.satisfies?("~> 1.2")# => true

Supported Package Managers

  • npm (Node.js): Caret ranges (^1.2.3), tilde ranges (~1.2.3), hyphen ranges (1.2.3 - 2.3.4), OR logic (||), wildcards (1.x, *)
  • RubyGems (Ruby): Pessimistic operator (~> 1.2), standard operators (>=, <=, etc.), comma-separated constraints
  • PyPI (Python): Comma-separated constraints (>=1.0,<2.0), exclusions (!=1.5.0), compatible release (~=1.4.2)
  • Maven (Java): Bracket notation ([1.0,2.0], (1.0,2.0)), union ranges, open ranges
  • NuGet (.NET): Bracket notation ([1.0,2.0], (1.0,2.0)), mixed brackets, open ranges
  • Packagist (PHP Composer): Caret ranges (^1.2.3), tilde ranges (~1.2), stability flags (@dev, @alpha)
  • Debian (apt): Standard comparison operators (>=1.0.0, <<2.0.0)
  • RPM (yum/dnf): Standard comparison operators (>=1.0.0, <=2.0.0)

Many other package managers are also supported using standard comparison operators (>=, <=, <, >, =, !=), including Cargo (Rust), Go modules, and more.

Mathematical Model

Internally, all version ranges are represented as mathematical intervals, similar to those used in mathematics:

  • [1.0.0, 2.0.0) represents versions from 1.0.0 (inclusive) to 2.0.0 (exclusive)
  • (1.0.0, 2.0.0] represents versions from 1.0.0 (exclusive) to 2.0.0 (inclusive)

This allows for precise set operations like union, intersection, and complement, regardless of the original package manager syntax.

Usage Examples

Basic Version Range Parsing

require'vers'# Parse vers URI formatrange=Vers.parse("vers:npm/>=1.2.3|<2.0.0")putsrange.contains?("1.5.0")# => trueputsrange.contains?("2.1.0")# => false# Parse native package manager syntaxnpm_range=Vers.parse_native("^1.2.3","npm")gem_range=Vers.parse_native("~> 1.0","gem")pypi_range=Vers.parse_native(">=1.0,<2.0","pypi")maven_range=Vers.parse_native("[1.0,2.0)","maven")

Creating Version Ranges

# Create exact version rangeexact=Vers.exact("1.2.3")putsexact.contains?("1.2.3")# => trueputsexact.contains?("1.2.4")# => false# Create comparison rangesgreater=Vers.greater_than("1.0.0",inclusive: true)less=Vers.less_than("2.0.0",inclusive: false)# Create unbounded and empty rangesall_versions=Vers.unboundedno_versions=Vers.empty

Converting Between Formats

# Parse native syntax and convert to vers URInpm_range=Vers.parse_native("^1.2.3","npm")vers_string=Vers.to_vers_string(npm_range,"npm")putsvers_string# => "vers:npm/>=1.2.3|<2.0.0"# Parse vers URI and use in your applicationrange=Vers.parse("vers:gem/~>1.0")putsrange.contains?("1.5.0")# => true

Set Operations on Version Ranges

range1=Vers.parse("vers:npm/>=1.0.0|<2.0.0")range2=Vers.parse("vers:npm/>=1.5.0|<3.0.0")# Union: versions in either rangeunion=range1.union(range2)putsunion.contains?("0.9.0")# => falseputsunion.contains?("1.2.0")# => trueputsunion.contains?("2.5.0")# => true# Intersection: versions in both rangesintersection=range1.intersect(range2)putsintersection.contains?("1.2.0")# => falseputsintersection.contains?("1.7.0")# => trueputsintersection.contains?("2.5.0")# => false# Complement: versions NOT in rangecomplement=range1.complementputscomplement.contains?("0.5.0")# => trueputscomplement.contains?("1.5.0")# => false# Exclusions: remove specific versionsexcluded=range1.exclude("1.5.0")putsexcluded.contains?("1.4.0")# => trueputsexcluded.contains?("1.5.0")# => falseputsexcluded.contains?("1.6.0")# => true

Version Comparison and Manipulation

version=Vers::Version.new("1.2.3-alpha.1+build.123")# Access version componentsputsversion.major# => 1putsversion.minor# => 2putsversion.patch# => 3putsversion.prerelease# => "alpha.1"putsversion.build# => "build.123"# Compare versionsputsVers.compare("1.2.3","1.2.4")# => -1putsVers.compare("2.0.0","1.9.9")# => 1putsVers.compare("1.0.0","1.0.0")# => 0# Increment versions (returns new Version objects)putsversion.increment_major# => #<Vers::Version "2.0.0">putsversion.increment_minor# => #<Vers::Version "1.3.0"> putsversion.increment_patch# => #<Vers::Version "1.2.4"># Version propertiesputsversion.stable?# => false (has prerelease)putsversion.prerelease?# => trueputsversion.to_h# => {major: 1, minor: 2, patch: 3, ...}

Constraint Checking

version=Vers::Version.new("1.2.5")# Pessimistic constraint checking (Ruby-style)putsversion.satisfies?("~> 1.2")# => true (>= 1.2.0, < 1.3.0)putsversion.satisfies?("~> 1.2.3")# => true (>= 1.2.3, < 1.3.0)putsversion.satisfies?("~> 1.3")# => false# General satisfaction checkingputsVers.satisfies?("1.5.0","vers:npm/>=1.0.0|<2.0.0")# => trueputsVers.satisfies?("1.5.0","^1.2.3","npm")# => true

Specification Compliance

This gem implements the PURL Version Range Specification, providing a universal way to express version ranges across different software packaging ecosystems.

Learn more about the motivation and design behind VERS in the presentation from Open Source Summit NA 2025 (slides PDF) by Eve Martin-Jones and Elitsa Bankova. The following table from their talk shows how different package managers express the same version constraints:

OperatorNPMCargoCarthageRubyGemsPyPIMavenNuGet
behavior with no op1.0.0^1.0.0⁴illegal1.0.0illegal*⁵>=1.0
= ===1.0======[1.0]⁵[1.0]⁸
>>>>>(1.0,)(1.0,)
>=>=>=>=>=>=1.0⁵1.0⁷ᵇᵃ
<<<<<(,1.0)(,1.0)
<=<=<=<=<=(,1.0](,1.0]
!=!=!=
^^
~~, ~>¹~~=
~>¹~>~>
wildcards* x X* x X**
OR||,
ANDspace,,
RANGE-[,],(,)⁶[,],(,)

This complexity across ecosystems is exactly why VERS provides a universal format that works consistently across all package managers.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/andrew/vers. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

Related Projects

  • purl - Ruby implementation of Package URL (PURL)
  • semantic_range - Semantic version parsing (JavaScript style)
  • univers - Python implementation of version ranges
  • versatile - Java implementation of version ranges

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Vers project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

About

A Ruby gem for parsing, comparing and sorting versions according to the VERS spec.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

12 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages