purl 0.1.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e7de702b0ba9b9da0dd4091b6f49ee949b19cf485f985dee0761136affda91b
4
- data.tar.gz: 548b678cc07601b20dd280b6190cdf92da492bd2d77442bae5ea6b4b499132e8
3
+ metadata.gz: 7b04edce0acf5c2872aea527f2b3845dcff94e8079d23ed394abd688779e335e
4
+ data.tar.gz: 504d83a02eb4b6574b42bbc790820c1f22335f594667d2e239e1edf2569d5300
5
5
  SHA512:
6
- metadata.gz: a8a265a747f396d695b46e720fcbc1062d79f9c5abe996d085ef090409bdc3d2096eaf5db0fc766494666b0a378eb40ff27ba578f290cd5fc38cccdc6bbe0ab9
7
- data.tar.gz: 37057faad88b6b7a415de251af36ef8e21df31d57c334a9c3247054fd6b654321514f6b781dd24392c138e6127107d3e1d5d4f8fab23e527def5feef222a2610
6
+ metadata.gz: 5a7e76a9dfb4042cece6132a19c390c0ab648335d2d4e9a5acb519310c1475c37030c9c20c7f4ef43f6027805c53d713a3e58c1b391bbea592f92f1bfefc3736
7
+ data.tar.gz: 1c8c1662e1f893b7f62278951778a59e3af27df05d2b61a54fb8b7cbb3b418ee00815f0996bcd4c93ae28290bd457c0c2cd0010327fb39cb886704444a573eb7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
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
+
1
8
  ## [Unreleased]
2
9
 
3
- ## [0.1.0] - 2025-07-24
10
+ ## [1.0.0] - 2025-01-24
11
+
12
+ ### Added
13
+ - 🎯 Comprehensive PURL parsing and validation with all 32 official package types
14
+ - 🔥 Namespaced error handling with contextual information (`InvalidSchemeError`, `InvalidTypeError`, `ValidationError`, etc.)
15
+ - 🔄 Bidirectional registry URL conversion - generate registry URLs from PURLs and parse PURLs from registry URLs
16
+ - 🌐 Registry URL generation for 13+ package ecosystems (npm, gem, maven, pypi, cargo, golang, etc.)
17
+ - 🎨 Rails-style route patterns for registry URL templates
18
+ - 📋 Type-specific validation for conan, cran, and swift packages
19
+ - 🤝 Cross-language compatibility with JSON-based configuration in `purl-types.json`
20
+ - 📊 69.5% compliance with official PURL specification test suite (41/59 tests passing)
21
+ - 🛠️ Comprehensive rake tasks for spec compliance testing and type management
22
+ - 📚 Full documentation and usage examples
23
+
24
+ ### Features
25
+ - Parse PURL strings with full component extraction (type, namespace, name, version, qualifiers, subpath)
26
+ - Create PURL objects programmatically with validation
27
+ - Generate registry URLs for supported package types
28
+ - Reverse parse registry URLs back to PURL objects
29
+ - Query package type information and capabilities
30
+ - Validate PURLs according to type-specific rules
31
+ - Support for all official PURL types from the specification
32
+
33
+ ### Supported Package Types
34
+ - **Registry URL Generation (13 types):** cargo, cocoapods, composer, conda, gem, golang, hex, maven, npm, nuget, pub, pypi, swift
35
+ - **Reverse Parsing (6 types):** cargo, gem, golang, maven, npm, pypi
36
+ - **All 32 Official Types:** alpm, apk, bitbucket, bitnami, cargo, cocoapods, composer, conan, conda, cpan, cran, deb, docker, gem, generic, github, golang, hackage, hex, huggingface, luarocks, maven, mlflow, npm, nuget, oci, pub, pypi, qpkg, rpm, swid, swift
37
+
38
+ ### Development Tools
39
+ - `rake spec:update` - Fetch latest test cases from official PURL spec repository
40
+ - `rake spec:compliance` - Run compliance tests against official test suite
41
+ - `rake spec:types` - Show information about all PURL types and their support
42
+ - `rake spec:verify_types` - Verify types list against official specification
43
+ - `rake spec:debug` - Show detailed info about failing test cases
4
44
 
5
- - Initial release
45
+ ### Major Release - Production Ready
46
+ This marks the first major release of the Purl gem, indicating API stability and production readiness. The library provides comprehensive PURL parsing with better error handling and more features than existing PURL libraries for Ruby, including bidirectional registry URL conversion and cross-language JSON configuration compatibility.
data/CODE_OF_CONDUCT.md CHANGED
@@ -60,7 +60,7 @@ representative at an online or offline event.
60
60
 
61
61
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
62
  reported to the community leaders responsible for enforcement at
63
- [INSERT CONTACT METHOD].
63
+ [andrew@ecosyste.ms](mailto:andrew@ecosyste.ms).
64
64
  All complaints will be reviewed and investigated promptly and fairly.
65
65
 
66
66
  All community leaders are obligated to respect the privacy and security of the
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Andrew Nesbitt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,39 +1,299 @@
1
- # Purl
1
+ # Purl - Package URL Parser for Ruby
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ A comprehensive Ruby library for parsing, validating, and working with Package URLs (PURLs) as defined by the [PURL specification](https://github.com/package-url/purl-spec).
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/purl`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ This library provides better error handling than existing solutions with namespaced error types, bidirectional registry URL conversion, and JSON-based configuration for cross-language compatibility.
6
+
7
+ [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%202.7-red.svg)](https://www.ruby-lang.org/)
8
+ [![Gem Version](https://badge.fury.io/rb/purl.svg)](https://rubygems.org/gems/purl)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
+
11
+ **🔗 [Available on RubyGems](https://rubygems.org/gems/purl)**
12
+
13
+ ## Features
14
+
15
+ - 🎯 **Comprehensive PURL parsing and validation** with 37 package types (32 official + 5 additional ecosystems)
16
+ - 🔥 **Better error handling** with namespaced error classes and contextual information
17
+ - 🔄 **Bidirectional registry URL conversion** - generate registry URLs from PURLs and parse PURLs from registry URLs
18
+ - 📋 **Type-specific validation** for conan, cran, and swift packages
19
+ - 🌐 **Registry URL generation** for 20 package ecosystems (npm, gem, maven, pypi, etc.)
20
+ - 🎨 **Rails-style route patterns** for registry URL templates
21
+ - 📊 **100% compliance** with official PURL specification test suite (59/59 tests passing)
22
+ - 🤝 **Cross-language compatibility** with JSON-based configuration
23
+ - 📚 **Comprehensive documentation** and examples
6
24
 
7
25
  ## Installation
8
26
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
27
+ Add this line to your application's Gemfile:
10
28
 
11
- Install the gem and add to the application's Gemfile by executing:
29
+ ```ruby
30
+ gem 'purl'
31
+ ```
32
+
33
+ And then execute:
12
34
 
13
35
  ```bash
14
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
36
+ bundle install
15
37
  ```
16
38
 
17
- If bundler is not being used to manage dependencies, install the gem by executing:
39
+ Or install it yourself as:
18
40
 
19
41
  ```bash
20
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
42
+ gem install purl
21
43
  ```
22
44
 
23
45
  ## Usage
24
46
 
25
- TODO: Write usage instructions here
47
+ ### Basic PURL Parsing
48
+
49
+ ```ruby
50
+ require 'purl'
51
+
52
+ # Parse a PURL string
53
+ purl = Purl.parse("pkg:gem/rails@7.0.0")
54
+ puts purl.type # => "gem"
55
+ puts purl.name # => "rails"
56
+ puts purl.version # => "7.0.0"
57
+ puts purl.namespace # => nil
58
+
59
+ # Parse with namespace and qualifiers
60
+ purl = Purl.parse("pkg:npm/@babel/core@7.0.0?arch=x86_64")
61
+ puts purl.type # => "npm"
62
+ puts purl.namespace # => "@babel"
63
+ puts purl.name # => "core"
64
+ puts purl.version # => "7.0.0"
65
+ puts purl.qualifiers # => {"arch" => "x86_64"}
66
+ ```
67
+
68
+ ### Creating PURLs
69
+
70
+ ```ruby
71
+ # Create a PURL object
72
+ purl = Purl::PackageURL.new(
73
+ type: "maven",
74
+ namespace: "org.apache.commons",
75
+ name: "commons-lang3",
76
+ version: "3.12.0"
77
+ )
78
+
79
+ puts purl.to_s # => "pkg:maven/org.apache.commons/commons-lang3@3.12.0"
80
+ ```
81
+
82
+ ### Registry URL Generation
83
+
84
+ ```ruby
85
+ # Generate registry URLs from PURLs
86
+ purl = Purl.parse("pkg:gem/rails@7.0.0")
87
+ puts purl.registry_url # => "https://rubygems.org/gems/rails"
88
+ puts purl.registry_url_with_version # => "https://rubygems.org/gems/rails/versions/7.0.0"
89
+
90
+ # Check if registry URL generation is supported
91
+ puts purl.supports_registry_url? # => true
92
+
93
+ # NPM with scoped packages
94
+ purl = Purl.parse("pkg:npm/@babel/core@7.0.0")
95
+ puts purl.registry_url # => "https://www.npmjs.com/package/@babel/core"
96
+ ```
97
+
98
+ ### Reverse Parsing: Registry URLs to PURLs
99
+
100
+ ```ruby
101
+ # Parse registry URLs back to PURLs
102
+ purl = Purl.from_registry_url("https://rubygems.org/gems/rails/versions/7.0.0")
103
+ puts purl.to_s # => "pkg:gem/rails@7.0.0"
104
+
105
+ # Works with various registries
106
+ purl = Purl.from_registry_url("https://www.npmjs.com/package/@babel/core")
107
+ puts purl.to_s # => "pkg:npm/@babel/core"
108
+
109
+ purl = Purl.from_registry_url("https://pypi.org/project/django/4.0.0/")
110
+ puts purl.to_s # => "pkg:pypi/django@4.0.0"
111
+ ```
112
+
113
+ ### Route Patterns
114
+
115
+ ```ruby
116
+ # Get route patterns for a package type (Rails-style)
117
+ patterns = Purl::RegistryURL.route_patterns_for("gem")
118
+ # => ["https://rubygems.org/gems/:name", "https://rubygems.org/gems/:name/versions/:version"]
119
+
120
+ # Get all route patterns
121
+ all_patterns = Purl::RegistryURL.all_route_patterns
122
+ puts all_patterns["npm"]
123
+ # => ["https://www.npmjs.com/package/:namespace/:name", "https://www.npmjs.com/package/:name", ...]
124
+ ```
125
+
126
+ ### Package Type Information
127
+
128
+ ```ruby
129
+ # Get all known PURL types
130
+ puts Purl.known_types.length # => 32
131
+ puts Purl.known_types.include?("gem") # => true
132
+
133
+ # Check type support
134
+ puts Purl.known_type?("gem") # => true
135
+ puts Purl.registry_supported_types # => ["cargo", "gem", "maven", "npm", ...]
136
+ puts Purl.reverse_parsing_supported_types # => ["cargo", "gem", "maven", "npm", ...]
137
+
138
+ # Get detailed type information
139
+ info = Purl.type_info("gem")
140
+ puts info[:known] # => true
141
+ puts info[:registry_url_generation] # => true
142
+ puts info[:reverse_parsing] # => true
143
+ puts info[:route_patterns] # => ["https://rubygems.org/gems/:name", ...]
144
+ ```
145
+
146
+ ### Error Handling
147
+
148
+ ```ruby
149
+ # Detailed error types with context
150
+ begin
151
+ Purl.parse("invalid-purl")
152
+ rescue Purl::InvalidSchemeError => e
153
+ puts "Scheme error: #{e.message}"
154
+ rescue Purl::ParseError => e
155
+ puts "Parse error: #{e.message}"
156
+ puts "Component: #{e.component}"
157
+ puts "Value: #{e.value}"
158
+ end
159
+
160
+ # Type-specific validation errors
161
+ begin
162
+ Purl::PackageURL.new(type: "swift", name: "Alamofire") # Swift requires namespace
163
+ rescue Purl::ValidationError => e
164
+ puts e.message # => "Swift PURLs require a namespace to be unambiguous"
165
+ end
166
+ ```
167
+
168
+ ### Supported Package Types
169
+
170
+ The library supports 37 package types (32 official + 5 additional ecosystems):
171
+
172
+ **Registry URL Generation (20 types):**
173
+ - `bioconductor` (R/Bioconductor) - bioconductor.org
174
+ - `cargo` (Rust) - crates.io
175
+ - `clojars` (Clojure) - clojars.org
176
+ - `cocoapods` (iOS) - cocoapods.org
177
+ - `composer` (PHP) - packagist.org
178
+ - `conda` (Python) - anaconda.org
179
+ - `cpan` (Perl) - metacpan.org
180
+ - `deno` (Deno) - deno.land/x
181
+ - `elm` (Elm) - package.elm-lang.org
182
+ - `gem` (Ruby) - rubygems.org
183
+ - `golang` (Go) - pkg.go.dev
184
+ - `hackage` (Haskell) - hackage.haskell.org
185
+ - `hex` (Elixir) - hex.pm
186
+ - `homebrew` (macOS) - formulae.brew.sh
187
+ - `maven` (Java) - mvnrepository.com
188
+ - `npm` (Node.js) - npmjs.com
189
+ - `nuget` (.NET) - nuget.org
190
+ - `pub` (Dart) - pub.dev
191
+ - `pypi` (Python) - pypi.org
192
+ - `swift` (Swift) - swiftpackageindex.com
193
+
194
+ **Reverse Parsing (10 types):**
195
+ - `cargo`, `deno`, `elm`, `gem`, `golang`, `hackage`, `homebrew`, `maven`, `npm`, `pypi`
196
+
197
+ **All 37 Supported Types:**
198
+ `alpm`, `apk`, `bioconductor`, `bitbucket`, `bitnami`, `cargo`, `clojars`, `cocoapods`, `composer`, `conan`, `conda`, `cpan`, `cran`, `deb`, `deno`, `docker`, `elm`, `gem`, `generic`, `github`, `golang`, `hackage`, `hex`, `homebrew`, `huggingface`, `luarocks`, `maven`, `mlflow`, `npm`, `nuget`, `oci`, `pub`, `pypi`, `qpkg`, `rpm`, `swid`, `swift`
199
+
200
+ ## Specification Compliance
201
+
202
+ - **100% compliance** with the official PURL specification test suite (59/59 tests passing)
203
+ - **All 32 official package types** plus 5 additional ecosystem types supported
204
+ - **Type-specific validation** for conan, cran, swift, cpan, and mlflow packages
205
+ - **Proper error handling** for invalid PURLs that should be rejected
206
+
207
+ ## JSON Configuration
208
+
209
+ Package types and registry patterns are stored in `purl-types.json` for easy contribution and cross-language compatibility:
210
+
211
+ ```json
212
+ {
213
+ "version": "1.0.0",
214
+ "description": "PURL types and registry URL patterns for package ecosystems",
215
+ "types": {
216
+ "gem": {
217
+ "description": "RubyGems",
218
+ "registry_support": true,
219
+ "registry_config": {
220
+ "base_url": "https://rubygems.org/gems",
221
+ "route_patterns": ["https://rubygems.org/gems/:name"],
222
+ "reverse_parsing": true
223
+ }
224
+ }
225
+ }
226
+ }
227
+ ```
26
228
 
27
229
  ## Development
28
230
 
29
- 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.
231
+ After checking out the repo, run `bin/setup` to install dependencies. Then:
232
+
233
+ ```bash
234
+ # Run tests
235
+ rake test
236
+
237
+ # Run specification compliance tests
238
+ rake spec:compliance
30
239
 
31
- 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).
240
+ # Update test cases from official PURL spec
241
+ rake spec:update
242
+
243
+ # Show type information
244
+ rake spec:types
245
+
246
+ # Verify types against official specification
247
+ rake spec:verify_types
248
+ ```
249
+
250
+ ### Rake Tasks
251
+
252
+ - `rake spec:update` - Fetch latest test cases from official PURL spec repository
253
+ - `rake spec:compliance` - Run compliance tests against official test suite
254
+ - `rake spec:types` - Show information about all PURL types and their support
255
+ - `rake spec:verify_types` - Verify our types list against official specification
256
+ - `rake spec:debug` - Show detailed info about failing test cases
257
+
258
+ ## Funding
259
+
260
+ If you find this project useful, please consider supporting its development:
261
+
262
+ - 💝 [GitHub Sponsors](https://github.com/sponsors/andrew)
263
+ - ☕ [Buy me a coffee](https://www.buymeacoffee.com/andrew)
264
+
265
+ Your support helps maintain and improve this library for the entire Ruby community.
32
266
 
33
267
  ## Contributing
34
268
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/purl. 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/[USERNAME]/purl/blob/main/CODE_OF_CONDUCT.md).
269
+ Bug reports and pull requests are welcome on GitHub. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
270
+
271
+ 1. Fork it
272
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
273
+ 3. Make your changes
274
+ 4. Add tests for your changes
275
+ 5. Ensure all tests pass (`rake test`)
276
+ 6. Commit your changes (`git commit -am 'Add some feature'`)
277
+ 7. Push to the branch (`git push origin my-new-feature`)
278
+ 8. Create new Pull Request
279
+
280
+ ### Adding New Package Types
281
+
282
+ To add support for a new package type:
283
+
284
+ 1. Update `purl-types.json` with the new type configuration
285
+ 2. Add registry URL patterns if applicable
286
+ 3. Add type-specific validation rules if needed in `lib/purl/package_url.rb`
287
+ 4. Add tests for the new functionality
288
+
289
+ ## License
290
+
291
+ This gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
292
+
293
+ ## Changelog
294
+
295
+ See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes and releases.
36
296
 
37
297
  ## Code of Conduct
38
298
 
39
- Everyone interacting in the Purl project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/purl/blob/main/CODE_OF_CONDUCT.md).
299
+ Everyone interacting in the Purl project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md).