vers 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +87 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/CONTRIBUTING.md +194 -0
- data/README.md +257 -0
- data/Rakefile +248 -0
- data/SECURITY.md +164 -0
- data/VERSION-RANGE-SPEC.rst +1009 -0
- data/lib/vers/constraint.rb +158 -0
- data/lib/vers/interval.rb +229 -0
- data/lib/vers/parser.rb +447 -0
- data/lib/vers/version.rb +338 -0
- data/lib/vers/version_range.rb +173 -0
- data/lib/vers.rb +215 -0
- data/sig/vers.rbs +4 -0
- data/test-suite-data.json +335 -0
- metadata +61 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ae79cd7ee206fc3d6a786291f57f0c3fd55c37cb0db864c2eba049cfb820542c
|
4
|
+
data.tar.gz: dc8b996bcc1aad44e585eab361dc396bcd0b5b864d9cc287553c55c036bcbe01
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1d9c6b0983644a8f52807a6dfa6d524f447c1856273bf6e86810c4c4f52767ebdd3c26bd77bc6ebff378f5147292b49d4636e9baed0576e1a1f2851dcd32248c
|
7
|
+
data.tar.gz: 0e7b47362f4f5ce6395d1785f92dcb21b71e737287d59547c95b11d0ed1b8c5979f5c80379df4a437c875d908639f72a2ce2a89ed4f74106faab5fffa4bab80f
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [1.0.0] - 2025-01-25
|
11
|
+
|
12
|
+
### Added
|
13
|
+
- **JSON Test Dataset** (`test-suite-data.json`) with 37 comprehensive test cases for cross-language compatibility
|
14
|
+
- **Enhanced NPM Support**: X-ranges (`1.2.x`), OR logic (`||`), wildcard support, invalid range validation
|
15
|
+
- **Maven Union Ranges**: Complex multi-range support like `"[2.0,2.3.1] , [2.4.0,2.12.2) , [2.13.0,2.15.0)"`
|
16
|
+
- **Prerelease Version Handling**: Caret and hyphen ranges with prerelease versions
|
17
|
+
- **Specification Compliance Tests**: Automated test suite validating VERS spec compliance
|
18
|
+
- **Cross-Ecosystem Compatibility Tests**: Verify equivalent ranges work across package managers
|
19
|
+
- **Bidirectional Conversion Tests**: Ensure parsing and regenerating produces equivalent results
|
20
|
+
- **Enhanced Rake Tasks**:
|
21
|
+
- `rake spec:compliance` - Run VERS specification compliance test suite
|
22
|
+
- `rake spec:test_data` - Show JSON test dataset information
|
23
|
+
- **Comprehensive Error Handling**: Invalid ranges like `"blerg"` and `"git+https://..."` raise proper errors
|
24
|
+
- **Maven Malformed Range Validation**: Detect and reject invalid bracket notation like `"(1.0.0]"`
|
25
|
+
|
26
|
+
### Enhanced
|
27
|
+
- **NPM Parser**: Added support for empty ranges, X-ranges, OR logic, and invalid range detection
|
28
|
+
- **Maven Parser**: Fixed union range parsing with proper bracket preservation
|
29
|
+
- **Test Coverage**: Expanded from 113 to 129 tests with 725 assertions, all passing
|
30
|
+
- **Documentation**: Added package manager syntax comparison table inspired by Eve Martin-Jones and Elitsa Bankova's presentation
|
31
|
+
|
32
|
+
## [0.1.0] - 2025-01-25
|
33
|
+
|
34
|
+
### Added
|
35
|
+
|
36
|
+
- **Initial release** of Vers Ruby gem for parsing, comparing and sorting versions according to the VERS specification
|
37
|
+
- **Mathematical interval model** for precise version range representation
|
38
|
+
- **Universal version range parsing** with support for 6 package ecosystems:
|
39
|
+
- npm (Node.js): Caret ranges (^1.2.3), tilde ranges (~1.2.3), hyphen ranges (1.2.3 - 2.3.4)
|
40
|
+
- gem (RubyGems): Pessimistic operator (~> 1.2), standard operators (>=, <=, etc.)
|
41
|
+
- pypi (Python): Comma-separated constraints (>=1.0,<2.0), exclusions (!=1.5.0)
|
42
|
+
- maven (Java): Bracket notation ([1.0,2.0], (1.0,2.0), [1.0,2.0))
|
43
|
+
- debian: Standard comparison operators (>=1.0.0, <<2.0.0)
|
44
|
+
- rpm: Standard comparison operators (>=1.0.0, <=2.0.0)
|
45
|
+
- **VERS URI format support** - parse and generate vers URI strings (e.g., `vers:npm/>=1.2.3|<2.0.0`)
|
46
|
+
- **Bidirectional conversion** between native package manager syntax and universal vers URI format
|
47
|
+
- **Set operations** on version ranges:
|
48
|
+
- Union: combine multiple version ranges
|
49
|
+
- Intersection: find overlapping versions
|
50
|
+
- Complement: find versions NOT in a range
|
51
|
+
- Exclusion: remove specific versions from ranges
|
52
|
+
- **Semantic versioning features** inspired by the semantic gem:
|
53
|
+
- Version increment methods (`increment_major`, `increment_minor`, `increment_patch`)
|
54
|
+
- Pessimistic constraint checking (`version.satisfies?("~> 1.2")`)
|
55
|
+
- Prerelease and build metadata support
|
56
|
+
- Version comparison and normalization
|
57
|
+
- **Comprehensive error handling** with detailed parsing exceptions
|
58
|
+
- **Core classes**:
|
59
|
+
- `Vers::Version` - semantic version parsing and comparison
|
60
|
+
- `Vers::Interval` - mathematical interval representation with bounds
|
61
|
+
- `Vers::VersionRange` - collection of intervals with set operations
|
62
|
+
- `Vers::Constraint` - individual version constraints (>=, <, etc.)
|
63
|
+
- `Vers::Parser` - extensible translation layer for package manager syntaxes
|
64
|
+
- **Complete test coverage** with 113 tests and 366 assertions
|
65
|
+
- **Comprehensive RDoc documentation** for all public APIs
|
66
|
+
- **Development tooling**:
|
67
|
+
- Rake tasks for specification validation and examples
|
68
|
+
- Security policy and contributing guidelines
|
69
|
+
- GitHub Actions-ready project structure
|
70
|
+
|
71
|
+
### Documentation
|
72
|
+
|
73
|
+
- **README.md** with comprehensive usage examples and API documentation
|
74
|
+
- **CONTRIBUTING.md** with development guidelines and project structure
|
75
|
+
- **SECURITY.md** with vulnerability reporting procedures
|
76
|
+
- **VERSION-RANGE-SPEC.rst** - official VERS specification included in repository
|
77
|
+
- **RDoc documentation** for all classes and methods
|
78
|
+
|
79
|
+
### Dependencies
|
80
|
+
|
81
|
+
- **Ruby 3.2+** required
|
82
|
+
- **No runtime dependencies** - pure Ruby implementation
|
83
|
+
- **Minitest** for testing (development dependency only)
|
84
|
+
|
85
|
+
[Unreleased]: https://github.com/andrew/vers/compare/v1.0.0...HEAD
|
86
|
+
[1.0.0]: https://github.com/andrew/vers/compare/v0.1.0...v1.0.0
|
87
|
+
[0.1.0]: https://github.com/andrew/vers/releases/tag/v0.1.0
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
9
|
+
nationality, personal appearance, race, caste, color, religion, or sexual
|
10
|
+
identity and orientation.
|
11
|
+
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
13
|
+
diverse, inclusive, and healthy community.
|
14
|
+
|
15
|
+
## Our Standards
|
16
|
+
|
17
|
+
Examples of behavior that contributes to a positive environment for our
|
18
|
+
community include:
|
19
|
+
|
20
|
+
* Demonstrating empathy and kindness toward other people
|
21
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
22
|
+
* Giving and gracefully accepting constructive feedback
|
23
|
+
* Accepting responsibility and apologizing to those affected by our mistakes,
|
24
|
+
and learning from the experience
|
25
|
+
* Focusing on what is best not just for us as individuals, but for the overall
|
26
|
+
community
|
27
|
+
|
28
|
+
Examples of unacceptable behavior include:
|
29
|
+
|
30
|
+
* The use of sexualized language or imagery, and sexual attention or advances of
|
31
|
+
any kind
|
32
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
33
|
+
* Public or private harassment
|
34
|
+
* Publishing others' private information, such as a physical or email address,
|
35
|
+
without their explicit permission
|
36
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
37
|
+
professional setting
|
38
|
+
|
39
|
+
## Enforcement Responsibilities
|
40
|
+
|
41
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
42
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
43
|
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
44
|
+
or harmful.
|
45
|
+
|
46
|
+
Community leaders have the right and responsibility to remove, edit, or reject
|
47
|
+
comments, commits, code, wiki edits, issues, and other contributions that are
|
48
|
+
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
49
|
+
decisions when appropriate.
|
50
|
+
|
51
|
+
## Scope
|
52
|
+
|
53
|
+
This Code of Conduct applies within all community spaces, and also applies when
|
54
|
+
an individual is officially representing the community in public spaces.
|
55
|
+
Examples of representing our community include using an official email address,
|
56
|
+
posting via an official social media account, or acting as an appointed
|
57
|
+
representative at an online or offline event.
|
58
|
+
|
59
|
+
## Enforcement
|
60
|
+
|
61
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
62
|
+
reported to the community leaders responsible for enforcement at
|
63
|
+
[INSERT CONTACT METHOD].
|
64
|
+
All complaints will be reviewed and investigated promptly and fairly.
|
65
|
+
|
66
|
+
All community leaders are obligated to respect the privacy and security of the
|
67
|
+
reporter of any incident.
|
68
|
+
|
69
|
+
## Enforcement Guidelines
|
70
|
+
|
71
|
+
Community leaders will follow these Community Impact Guidelines in determining
|
72
|
+
the consequences for any action they deem in violation of this Code of Conduct:
|
73
|
+
|
74
|
+
### 1. Correction
|
75
|
+
|
76
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed
|
77
|
+
unprofessional or unwelcome in the community.
|
78
|
+
|
79
|
+
**Consequence**: A private, written warning from community leaders, providing
|
80
|
+
clarity around the nature of the violation and an explanation of why the
|
81
|
+
behavior was inappropriate. A public apology may be requested.
|
82
|
+
|
83
|
+
### 2. Warning
|
84
|
+
|
85
|
+
**Community Impact**: A violation through a single incident or series of
|
86
|
+
actions.
|
87
|
+
|
88
|
+
**Consequence**: A warning with consequences for continued behavior. No
|
89
|
+
interaction with the people involved, including unsolicited interaction with
|
90
|
+
those enforcing the Code of Conduct, for a specified period of time. This
|
91
|
+
includes avoiding interactions in community spaces as well as external channels
|
92
|
+
like social media. Violating these terms may lead to a temporary or permanent
|
93
|
+
ban.
|
94
|
+
|
95
|
+
### 3. Temporary Ban
|
96
|
+
|
97
|
+
**Community Impact**: A serious violation of community standards, including
|
98
|
+
sustained inappropriate behavior.
|
99
|
+
|
100
|
+
**Consequence**: A temporary ban from any sort of interaction or public
|
101
|
+
communication with the community for a specified period of time. No public or
|
102
|
+
private interaction with the people involved, including unsolicited interaction
|
103
|
+
with those enforcing the Code of Conduct, is allowed during this period.
|
104
|
+
Violating these terms may lead to a permanent ban.
|
105
|
+
|
106
|
+
### 4. Permanent Ban
|
107
|
+
|
108
|
+
**Community Impact**: Demonstrating a pattern of violation of community
|
109
|
+
standards, including sustained inappropriate behavior, harassment of an
|
110
|
+
individual, or aggression toward or disparagement of classes of individuals.
|
111
|
+
|
112
|
+
**Consequence**: A permanent ban from any sort of public interaction within the
|
113
|
+
community.
|
114
|
+
|
115
|
+
## Attribution
|
116
|
+
|
117
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
118
|
+
version 2.1, available at
|
119
|
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
120
|
+
|
121
|
+
Community Impact Guidelines were inspired by
|
122
|
+
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
123
|
+
|
124
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
125
|
+
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
126
|
+
[https://www.contributor-covenant.org/translations][translations].
|
127
|
+
|
128
|
+
[homepage]: https://www.contributor-covenant.org
|
129
|
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
130
|
+
[Mozilla CoC]: https://github.com/mozilla/diversity
|
131
|
+
[FAQ]: https://www.contributor-covenant.org/faq
|
132
|
+
[translations]: https://www.contributor-covenant.org/translations
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
# Contributing to Vers
|
2
|
+
|
3
|
+
Thank you for your interest in contributing to the Vers Ruby library! This document provides guidelines and information for contributors.
|
4
|
+
|
5
|
+
## Code of Conduct
|
6
|
+
|
7
|
+
This project and everyone participating in it is governed by our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.
|
8
|
+
|
9
|
+
## How to Contribute
|
10
|
+
|
11
|
+
### Reporting Issues
|
12
|
+
|
13
|
+
Before creating an issue, please:
|
14
|
+
1. Search existing issues to avoid duplicates
|
15
|
+
2. Use the latest version of the gem
|
16
|
+
3. Provide a clear, descriptive title
|
17
|
+
4. Include steps to reproduce the issue
|
18
|
+
5. Share relevant code examples or error messages
|
19
|
+
|
20
|
+
### Suggesting Enhancements
|
21
|
+
|
22
|
+
Enhancement suggestions are welcome! Please:
|
23
|
+
1. Check if the enhancement is already requested
|
24
|
+
2. Explain the use case and expected behavior
|
25
|
+
3. Consider if it fits the project's scope
|
26
|
+
4. Be willing to help implement if accepted
|
27
|
+
|
28
|
+
### Pull Requests
|
29
|
+
|
30
|
+
1. **Fork** the repository
|
31
|
+
2. **Create** a feature branch (`git checkout -b my-new-feature`)
|
32
|
+
3. **Make** your changes following our coding standards
|
33
|
+
4. **Add** tests for your changes
|
34
|
+
5. **Ensure** all tests pass (`rake test`)
|
35
|
+
6. **Run** the full test suite including any compliance tests
|
36
|
+
7. **Commit** your changes with clear, descriptive messages
|
37
|
+
8. **Push** to your branch (`git push origin my-new-feature`)
|
38
|
+
9. **Create** a Pull Request with a clear description
|
39
|
+
|
40
|
+
## Development Setup
|
41
|
+
|
42
|
+
### Prerequisites
|
43
|
+
|
44
|
+
- Ruby 3.2 or higher
|
45
|
+
- Bundler gem
|
46
|
+
|
47
|
+
### Setup
|
48
|
+
|
49
|
+
```bash
|
50
|
+
git clone https://github.com/andrew/vers.git
|
51
|
+
cd vers
|
52
|
+
bundle install
|
53
|
+
```
|
54
|
+
|
55
|
+
### Running Tests
|
56
|
+
|
57
|
+
```bash
|
58
|
+
# Run all tests
|
59
|
+
rake test
|
60
|
+
|
61
|
+
# Run tests with coverage
|
62
|
+
bundle exec rake test
|
63
|
+
|
64
|
+
# Show all available tasks
|
65
|
+
rake -T
|
66
|
+
```
|
67
|
+
|
68
|
+
### Coding Standards
|
69
|
+
|
70
|
+
- Follow Ruby best practices and conventions
|
71
|
+
- Use meaningful variable and method names
|
72
|
+
- Add RDoc documentation for public methods
|
73
|
+
- Keep methods focused and concise
|
74
|
+
- Follow the existing code style
|
75
|
+
- Use `frozen_string_literal: true` at the top of all files
|
76
|
+
|
77
|
+
### Testing Requirements
|
78
|
+
|
79
|
+
All contributions must include appropriate tests:
|
80
|
+
|
81
|
+
- **Unit tests** for new functionality
|
82
|
+
- **Integration tests** for feature interactions
|
83
|
+
- **Edge case tests** for boundary conditions
|
84
|
+
- **Error handling tests** for exception cases
|
85
|
+
|
86
|
+
### Documentation
|
87
|
+
|
88
|
+
- Update the README.md if adding new features
|
89
|
+
- Add RDoc documentation for complex methods
|
90
|
+
- Update CHANGELOG.md following the format
|
91
|
+
- Include examples in documentation
|
92
|
+
|
93
|
+
## Project Structure
|
94
|
+
|
95
|
+
```
|
96
|
+
├── lib/
|
97
|
+
│ ├── vers.rb # Main module
|
98
|
+
│ └── vers/
|
99
|
+
│ ├── version.rb # Version class with semantic versioning
|
100
|
+
│ ├── interval.rb # Mathematical interval model
|
101
|
+
│ ├── version_range.rb # Version range operations
|
102
|
+
│ ├── constraint.rb # Individual version constraints
|
103
|
+
│ └── parser.rb # Package manager syntax parsers
|
104
|
+
├── test/ # Test files
|
105
|
+
├── VERSION-RANGE-SPEC.rst # Official specification
|
106
|
+
└── README.md # Project documentation
|
107
|
+
```
|
108
|
+
|
109
|
+
## Adding New Package Manager Support
|
110
|
+
|
111
|
+
To add support for a new package manager:
|
112
|
+
|
113
|
+
1. **Add parser methods** to `lib/vers/parser.rb`
|
114
|
+
2. **Include examples** in documentation
|
115
|
+
3. **Add comprehensive tests** for the new syntax
|
116
|
+
4. **Update README** with supported syntax examples
|
117
|
+
5. **Verify** against VERS specification compliance
|
118
|
+
|
119
|
+
## Version Range Operations
|
120
|
+
|
121
|
+
When working with version ranges:
|
122
|
+
|
123
|
+
1. **Use interval model** for internal representation
|
124
|
+
2. **Test set operations** (union, intersection, complement)
|
125
|
+
3. **Verify mathematical correctness** of operations
|
126
|
+
4. **Handle edge cases** like empty and unbounded ranges
|
127
|
+
|
128
|
+
## VERS Specification Compliance
|
129
|
+
|
130
|
+
This library maintains compliance with the VERS specification:
|
131
|
+
|
132
|
+
- All changes must maintain specification compliance
|
133
|
+
- New features should align with the spec
|
134
|
+
- Report spec issues upstream when discovered
|
135
|
+
- Test against official specification examples
|
136
|
+
|
137
|
+
## Release Process
|
138
|
+
|
139
|
+
Releases are handled by maintainers:
|
140
|
+
|
141
|
+
1. Update version in `lib/vers/version.rb`
|
142
|
+
2. Update `CHANGELOG.md` with changes
|
143
|
+
3. Run full test suite
|
144
|
+
4. Create release tag
|
145
|
+
5. Publish to RubyGems
|
146
|
+
|
147
|
+
## Getting Help
|
148
|
+
|
149
|
+
- **Issues**: Use GitHub issues for bugs and feature requests
|
150
|
+
- **Discussions**: Use GitHub discussions for questions
|
151
|
+
- **Security**: Follow our [Security Policy](SECURITY.md)
|
152
|
+
|
153
|
+
## Recognition
|
154
|
+
|
155
|
+
Contributors will be recognized in:
|
156
|
+
- Git commit history
|
157
|
+
- CHANGELOG.md for significant contributions
|
158
|
+
- Project documentation where appropriate
|
159
|
+
|
160
|
+
## License
|
161
|
+
|
162
|
+
By contributing to Vers, you agree that your contributions will be licensed under the [MIT License](LICENSE).
|
163
|
+
|
164
|
+
## Development Philosophy
|
165
|
+
|
166
|
+
### Mathematical Accuracy
|
167
|
+
|
168
|
+
Version ranges are implemented using mathematical interval theory:
|
169
|
+
- Intervals have clear bounds and inclusivity rules
|
170
|
+
- Set operations follow mathematical principles
|
171
|
+
- Edge cases are handled consistently
|
172
|
+
|
173
|
+
### Extensibility
|
174
|
+
|
175
|
+
The architecture supports easy extension:
|
176
|
+
- New package managers can be added via parser methods
|
177
|
+
- Version comparison logic is centralized
|
178
|
+
- Testing framework supports new syntax validation
|
179
|
+
|
180
|
+
### Performance
|
181
|
+
|
182
|
+
Consider performance implications:
|
183
|
+
- Avoid excessive regular expression backtracking
|
184
|
+
- Cache compiled patterns where appropriate
|
185
|
+
- Test with large version lists
|
186
|
+
|
187
|
+
### Error Handling
|
188
|
+
|
189
|
+
Provide clear, actionable error messages:
|
190
|
+
- Include context about what failed
|
191
|
+
- Suggest corrections when possible
|
192
|
+
- Use specific exception types
|
193
|
+
|
194
|
+
Thank you for contributing to make Vers better for everyone!
|
data/README.md
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
# Vers - Version Range Parser for Ruby
|
2
|
+
|
3
|
+
A Ruby library for parsing, comparing and sorting versions according to the [VERS specification](https://github.com/package-url/purl-spec/blob/main/VERSION-RANGE-SPEC.rst).
|
4
|
+
|
5
|
+
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.
|
6
|
+
|
7
|
+
[](https://www.ruby-lang.org/)
|
8
|
+
[](https://rubygems.org/gems/vers)
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
10
|
+
|
11
|
+
**[Available on RubyGems](https://rubygems.org/gems/vers)** | **[API Documentation](https://rdoc.info/github/andrew/vers)** | **[GitHub Repository](https://github.com/andrew/vers)**
|
12
|
+
|
13
|
+
## Features
|
14
|
+
|
15
|
+
- **Universal version range parsing** with support for 6 package ecosystems (npm, gem, pypi, maven, debian, rpm)
|
16
|
+
- **Mathematical interval model** for precise set operations (union, intersection, complement)
|
17
|
+
- **VERS specification compliance** with full support for the Package URL version range specification
|
18
|
+
- **Native syntax support** - parse native package manager syntax (^1.2.3, ~>1.0, >=1.0,<2.0, [1.0,2.0))
|
19
|
+
- **Bidirectional conversion** between native syntax and universal vers URI format
|
20
|
+
- **Semantic versioning features** - version increment, constraint checking, prerelease handling
|
21
|
+
- **Comprehensive error handling** with detailed parsing exceptions
|
22
|
+
- **100% test coverage** with 113 tests and 366 assertions
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add this line to your application's Gemfile:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
gem 'vers'
|
30
|
+
```
|
31
|
+
|
32
|
+
And then execute:
|
33
|
+
|
34
|
+
```bash
|
35
|
+
bundle install
|
36
|
+
```
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
```bash
|
41
|
+
gem install vers
|
42
|
+
```
|
43
|
+
|
44
|
+
## Quick Start
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
require 'vers'
|
48
|
+
|
49
|
+
# Parse a vers URI
|
50
|
+
range = Vers.parse("vers:npm/>=1.2.3|<2.0.0")
|
51
|
+
range.contains?("1.5.0") # => true
|
52
|
+
range.contains?("2.1.0") # => false
|
53
|
+
|
54
|
+
# Parse native package manager syntax
|
55
|
+
npm_range = Vers.parse_native("^1.2.3", "npm")
|
56
|
+
gem_range = Vers.parse_native("~> 1.0", "gem")
|
57
|
+
|
58
|
+
# Check version containment
|
59
|
+
Vers.satisfies?("1.5.0", ">=1.0.0,<2.0.0") # => true
|
60
|
+
|
61
|
+
# Compare versions
|
62
|
+
Vers.compare("1.2.3", "1.2.4") # => -1
|
63
|
+
|
64
|
+
# Version operations
|
65
|
+
version = Vers::Version.new("1.2.3")
|
66
|
+
version.increment_major # => #<Vers::Version "2.0.0">
|
67
|
+
version.satisfies?("~> 1.2") # => true
|
68
|
+
```
|
69
|
+
|
70
|
+
## Supported Package Managers
|
71
|
+
|
72
|
+
- **npm**: Caret ranges (^1.2.3), tilde ranges (~1.2.3), hyphen ranges (1.2.3 - 2.3.4)
|
73
|
+
- **RubyGems**: Pessimistic operator (~> 1.2), standard operators (>=, <=, etc.)
|
74
|
+
- **PyPI**: Comma-separated constraints (>=1.0,<2.0)
|
75
|
+
- **Maven**: Bracket notation ([1.0,2.0], (1.0,2.0))
|
76
|
+
- **Debian/RPM**: Standard comparison operators
|
77
|
+
|
78
|
+
## Mathematical Model
|
79
|
+
|
80
|
+
Internally, all version ranges are represented as mathematical intervals, similar to those used in mathematics:
|
81
|
+
|
82
|
+
- `[1.0.0, 2.0.0)` represents versions from 1.0.0 (inclusive) to 2.0.0 (exclusive)
|
83
|
+
- `(1.0.0, 2.0.0]` represents versions from 1.0.0 (exclusive) to 2.0.0 (inclusive)
|
84
|
+
|
85
|
+
This allows for precise set operations like union, intersection, and complement, regardless of the original package manager syntax.
|
86
|
+
|
87
|
+
## Usage Examples
|
88
|
+
|
89
|
+
### Basic Version Range Parsing
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
require 'vers'
|
93
|
+
|
94
|
+
# Parse vers URI format
|
95
|
+
range = Vers.parse("vers:npm/>=1.2.3|<2.0.0")
|
96
|
+
puts range.contains?("1.5.0") # => true
|
97
|
+
puts range.contains?("2.1.0") # => false
|
98
|
+
|
99
|
+
# Parse native package manager syntax
|
100
|
+
npm_range = Vers.parse_native("^1.2.3", "npm")
|
101
|
+
gem_range = Vers.parse_native("~> 1.0", "gem")
|
102
|
+
pypi_range = Vers.parse_native(">=1.0,<2.0", "pypi")
|
103
|
+
maven_range = Vers.parse_native("[1.0,2.0)", "maven")
|
104
|
+
```
|
105
|
+
|
106
|
+
### Creating Version Ranges
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
# Create exact version range
|
110
|
+
exact = Vers.exact("1.2.3")
|
111
|
+
puts exact.contains?("1.2.3") # => true
|
112
|
+
puts exact.contains?("1.2.4") # => false
|
113
|
+
|
114
|
+
# Create comparison ranges
|
115
|
+
greater = Vers.greater_than("1.0.0", inclusive: true)
|
116
|
+
less = Vers.less_than("2.0.0", inclusive: false)
|
117
|
+
|
118
|
+
# Create unbounded and empty ranges
|
119
|
+
all_versions = Vers.unbounded
|
120
|
+
no_versions = Vers.empty
|
121
|
+
```
|
122
|
+
|
123
|
+
### Converting Between Formats
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
# Parse native syntax and convert to vers URI
|
127
|
+
npm_range = Vers.parse_native("^1.2.3", "npm")
|
128
|
+
vers_string = Vers.to_vers_string(npm_range, "npm")
|
129
|
+
puts vers_string # => "vers:npm/>=1.2.3|<2.0.0"
|
130
|
+
|
131
|
+
# Parse vers URI and use in your application
|
132
|
+
range = Vers.parse("vers:gem/~>1.0")
|
133
|
+
puts range.contains?("1.5.0") # => true
|
134
|
+
```
|
135
|
+
|
136
|
+
### Set Operations on Version Ranges
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
range1 = Vers.parse("vers:npm/>=1.0.0|<2.0.0")
|
140
|
+
range2 = Vers.parse("vers:npm/>=1.5.0|<3.0.0")
|
141
|
+
|
142
|
+
# Union: versions in either range
|
143
|
+
union = range1.union(range2)
|
144
|
+
puts union.contains?("0.9.0") # => false
|
145
|
+
puts union.contains?("1.2.0") # => true
|
146
|
+
puts union.contains?("2.5.0") # => true
|
147
|
+
|
148
|
+
# Intersection: versions in both ranges
|
149
|
+
intersection = range1.intersect(range2)
|
150
|
+
puts intersection.contains?("1.2.0") # => false
|
151
|
+
puts intersection.contains?("1.7.0") # => true
|
152
|
+
puts intersection.contains?("2.5.0") # => false
|
153
|
+
|
154
|
+
# Complement: versions NOT in range
|
155
|
+
complement = range1.complement
|
156
|
+
puts complement.contains?("0.5.0") # => true
|
157
|
+
puts complement.contains?("1.5.0") # => false
|
158
|
+
|
159
|
+
# Exclusions: remove specific versions
|
160
|
+
excluded = range1.exclude("1.5.0")
|
161
|
+
puts excluded.contains?("1.4.0") # => true
|
162
|
+
puts excluded.contains?("1.5.0") # => false
|
163
|
+
puts excluded.contains?("1.6.0") # => true
|
164
|
+
```
|
165
|
+
|
166
|
+
### Version Comparison and Manipulation
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
version = Vers::Version.new("1.2.3-alpha.1+build.123")
|
170
|
+
|
171
|
+
# Access version components
|
172
|
+
puts version.major # => 1
|
173
|
+
puts version.minor # => 2
|
174
|
+
puts version.patch # => 3
|
175
|
+
puts version.prerelease # => "alpha.1"
|
176
|
+
puts version.build # => "build.123"
|
177
|
+
|
178
|
+
# Compare versions
|
179
|
+
puts Vers.compare("1.2.3", "1.2.4") # => -1
|
180
|
+
puts Vers.compare("2.0.0", "1.9.9") # => 1
|
181
|
+
puts Vers.compare("1.0.0", "1.0.0") # => 0
|
182
|
+
|
183
|
+
# Increment versions (returns new Version objects)
|
184
|
+
puts version.increment_major # => #<Vers::Version "2.0.0">
|
185
|
+
puts version.increment_minor # => #<Vers::Version "1.3.0">
|
186
|
+
puts version.increment_patch # => #<Vers::Version "1.2.4">
|
187
|
+
|
188
|
+
# Version properties
|
189
|
+
puts version.stable? # => false (has prerelease)
|
190
|
+
puts version.prerelease? # => true
|
191
|
+
puts version.to_h # => {major: 1, minor: 2, patch: 3, ...}
|
192
|
+
```
|
193
|
+
|
194
|
+
### Constraint Checking
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
version = Vers::Version.new("1.2.5")
|
198
|
+
|
199
|
+
# Pessimistic constraint checking (Ruby-style)
|
200
|
+
puts version.satisfies?("~> 1.2") # => true (>= 1.2.0, < 1.3.0)
|
201
|
+
puts version.satisfies?("~> 1.2.3") # => true (>= 1.2.3, < 1.3.0)
|
202
|
+
puts version.satisfies?("~> 1.3") # => false
|
203
|
+
|
204
|
+
# General satisfaction checking
|
205
|
+
puts Vers.satisfies?("1.5.0", "vers:npm/>=1.0.0|<2.0.0") # => true
|
206
|
+
puts Vers.satisfies?("1.5.0", "^1.2.3", "npm") # => true
|
207
|
+
```
|
208
|
+
|
209
|
+
## Specification Compliance
|
210
|
+
|
211
|
+
This gem implements the [PURL Version Range Specification](https://github.com/package-url/purl-spec/blob/main/VERSION-RANGE-SPEC.rst), providing a universal way to express version ranges across different software packaging ecosystems.
|
212
|
+
|
213
|
+
Learn more about the motivation and design behind VERS in the [presentation from Open Source Summit NA 2025](https://www.youtube.com/watch?v=EU-TodN27rM) ([slides PDF](https://static.sched.com/hosted_files/ossna2025/74/We%20need%20a%20standard%20for%20open%20source%20package%20requirements.pdf)) by Eve Martin-Jones and Elitsa Bankova. The following table from their talk shows how different package managers express the same version constraints:
|
214
|
+
|
215
|
+
| Operator | NPM | Cargo | Carthage | RubyGems | PyPI | Maven | NuGet |
|
216
|
+
|----------|-----|-------|----------|----------|------|-------|--------|
|
217
|
+
| **behavior with no op** | 1.0.0 | ^1.0.0⁴ | illegal | 1.0.0 | illegal | *⁵ | >=1.0 |
|
218
|
+
| **= ==** | =1.0 | = | == | = | == | [1.0]⁵ | [1.0]⁸ |
|
219
|
+
| **>** | > | > | | > | > | (1.0,) | (1.0,) |
|
220
|
+
| **>=** | >= | >= | >= | >= | >= | 1.0⁵ | 1.0⁷ᵇᵃ |
|
221
|
+
| **<** | < | < | | < | < | (,1.0) | (,1.0) |
|
222
|
+
| **<=** | <= | <= | | <= | <= | (,1.0] | (,1.0] |
|
223
|
+
| **!=** | | | | != | != | | |
|
224
|
+
| **^** | ^ | ^² | | | | | |
|
225
|
+
| **~** | ~, ~>¹ | ~ | | | ~= | | |
|
226
|
+
| **~>** | ¹ | | ~> | ~> | | | |
|
227
|
+
| **wildcards** | * x X | * x X | | | * | * | |
|
228
|
+
| **OR** | \|\| | | | | | , | |
|
229
|
+
| **AND** | space | , | | ,³ | , | | |
|
230
|
+
| **RANGE** | - | | | | | [,],(,)⁶ | [,],(,) |
|
231
|
+
|
232
|
+
This complexity across ecosystems is exactly why VERS provides a universal format that works consistently across all package managers.
|
233
|
+
|
234
|
+
## Development
|
235
|
+
|
236
|
+
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.
|
237
|
+
|
238
|
+
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](https://rubygems.org).
|
239
|
+
|
240
|
+
## Contributing
|
241
|
+
|
242
|
+
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](https://github.com/andrew/vers/blob/main/CODE_OF_CONDUCT.md).
|
243
|
+
|
244
|
+
## Related Projects
|
245
|
+
|
246
|
+
- [purl](https://github.com/andrew/purl) - Ruby implementation of Package URL (PURL)
|
247
|
+
- [semantic_range](https://github.com/librariesio/semantic_range) - Semantic version parsing (JavaScript style)
|
248
|
+
- [univers](https://github.com/package-url/univers) - Python implementation of version ranges
|
249
|
+
- [versatile](https://github.com/package-url/versatile) - Java implementation of version ranges
|
250
|
+
|
251
|
+
## License
|
252
|
+
|
253
|
+
The gem is available as open source under the terms of the MIT License.
|
254
|
+
|
255
|
+
## Code of Conduct
|
256
|
+
|
257
|
+
Everyone interacting in the Vers project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/andrew/vers/blob/main/CODE_OF_CONDUCT.md).
|