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.
Available on RubyGems | API Documentation | GitHub Repository
Add this line to your application's Gemfile:
And then execute:
Or install it yourself as:
require 'vers' # Parse a vers URI range = Vers.parse("vers:npm/>=1.2.3|<2.0.0") range.contains?("1.5.0") # => true range.contains?("2.1.0") # => false # Parse native package manager syntax npm_range = Vers.parse_native("^1.2.3", "npm") gem_range = Vers.parse_native("~> 1.0", "gem") # Check version containment Vers.satisfies?("1.5.0", ">=1.0.0,<2.0.0") # => true # Compare versions Vers.compare("1.2.3", "1.2.4") # => -1 # Version operations version = Vers::Version.new("1.2.3") version.increment_major # => #<Vers::Version "2.0.0"> version.satisfies?("~> 1.2") # => trueSupported Package Managers
Many other package managers are also supported using standard comparison operators (>=, <=, <, >, =, !=), including Cargo (Rust), Go modules, and more.
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.
Basic Version Range Parsingrequire 'vers' # Parse vers URI format range = Vers.parse("vers:npm/>=1.2.3|<2.0.0") puts range.contains?("1.5.0") # => true puts range.contains?("2.1.0") # => false # Parse native package manager syntax npm_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")
# Create exact version range exact = Vers.exact("1.2.3") puts exact.contains?("1.2.3") # => true puts exact.contains?("1.2.4") # => false # Create comparison ranges greater = Vers.greater_than("1.0.0", inclusive: true) less = Vers.less_than("2.0.0", inclusive: false) # Create unbounded and empty ranges all_versions = Vers.unbounded no_versions = Vers.emptyConverting Between Formats
# Parse native syntax and convert to vers URI npm_range = Vers.parse_native("^1.2.3", "npm") vers_string = Vers.to_vers_string(npm_range, "npm") puts vers_string # => "vers:npm/>=1.2.3|<2.0.0" # Parse vers URI and use in your application range = Vers.parse("vers:gem/~>1.0") puts range.contains?("1.5.0") # => trueSet 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 range union = range1.union(range2) puts union.contains?("0.9.0") # => false puts union.contains?("1.2.0") # => true puts union.contains?("2.5.0") # => true # Intersection: versions in both ranges intersection = range1.intersect(range2) puts intersection.contains?("1.2.0") # => false puts intersection.contains?("1.7.0") # => true puts intersection.contains?("2.5.0") # => false # Complement: versions NOT in range complement = range1.complement puts complement.contains?("0.5.0") # => true puts complement.contains?("1.5.0") # => false # Exclusions: remove specific versions excluded = range1.exclude("1.5.0") puts excluded.contains?("1.4.0") # => true puts excluded.contains?("1.5.0") # => false puts excluded.contains?("1.6.0") # => trueVersion Comparison and Manipulation
version = Vers::Version.new("1.2.3-alpha.1+build.123") # Access version components puts version.major # => 1 puts version.minor # => 2 puts version.patch # => 3 puts version.prerelease # => "alpha.1" puts version.build # => "build.123" # Compare versions puts Vers.compare("1.2.3", "1.2.4") # => -1 puts Vers.compare("2.0.0", "1.9.9") # => 1 puts Vers.compare("1.0.0", "1.0.0") # => 0 # Increment versions (returns new Version objects) puts version.increment_major # => #<Vers::Version "2.0.0"> puts version.increment_minor # => #<Vers::Version "1.3.0"> puts version.increment_patch # => #<Vers::Version "1.2.4"> # Version properties puts version.stable? # => false (has prerelease) puts version.prerelease? # => true puts version.to_h # => {major: 1, minor: 2, patch: 3, ...}
version = Vers::Version.new("1.2.5") # Pessimistic constraint checking (Ruby-style) puts version.satisfies?("~> 1.2") # => true (>= 1.2.0, < 1.3.0) puts version.satisfies?("~> 1.2.3") # => true (>= 1.2.3, < 1.3.0) puts version.satisfies?("~> 1.3") # => false # General satisfaction checking puts Vers.satisfies?("1.5.0", "vers:npm/>=1.0.0|<2.0.0") # => true puts Vers.satisfies?("1.5.0", "^1.2.3", "npm") # => true
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:
Operator NPM Cargo Carthage RubyGems PyPI Maven NuGet behavior with no op 1.0.0 ^1.0.0⁴ illegal 1.0.0 illegal *⁵ >=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 || , AND space , ,³ , RANGE - [,],(,)⁶ [,],(,)This complexity across ecosystems is exactly why VERS provides a universal format that works consistently across all package managers.
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.
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.
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the Vers project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4