diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 11b03e5..cbd4520 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,10 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ["2.7", "3.0"] - - env: - RUBYOPT: "-W:no-experimental" + ruby-version: ["3.2", "3.3", "3.4"] steps: - uses: actions/checkout@v2 diff --git a/.rubocop.yml b/.rubocop.yml index 3059293..8738d9f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,6 +1,7 @@ AllCops: - TargetRubyVersion: 2.7 + TargetRubyVersion: 3.2 NewCops: enable + SuggestExtensions: false Metrics/AbcSize: Enabled: false Metrics/BlockLength: @@ -18,6 +19,6 @@ Metrics/MethodLength: Metrics/ParameterLists: Max: 7 Metrics/PerceivedComplexity: - Max: 15 + Max: 20 Style/ConditionalAssignment: Enabled: false diff --git a/.ruby-version b/.ruby-version index cb2b00e..4d9d11c 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.0.1 +3.4.2 diff --git a/Gemfile b/Gemfile index 17a7b7a..2ffda61 100644 --- a/Gemfile +++ b/Gemfile @@ -7,8 +7,8 @@ gemspec gem 'bundler', '~> 2.0' gem 'rake', '~> 13.0' gem 'rspec', '~> 3.0' -gem 'rubocop', '~> 1.23.0' -gem 'rubocop-rake', '~> 0.6.0' -gem 'rubocop-rspec', '~> 2.6.0' -gem 'steep', '~> 0.46.0' +gem 'rubocop', '~> 1.74' +gem 'rubocop-rake', '~> 0.7' +gem 'rubocop-rspec', '~> 2.19' +gem 'steep', '~> 1.10.0' gem 'yard', '~> 0.9.0' diff --git a/Gemfile.lock b/Gemfile.lock index 3c23919..4aba427 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,93 +6,159 @@ PATH GEM remote: https://rubygems.org/ specs: - activesupport (7.0.4.3) - concurrent-ruby (~> 1.0, >= 1.0.2) + activesupport (8.0.2) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - tzinfo (~> 2.0) - ast (2.4.2) - concurrent-ruby (1.2.2) - diff-lcs (1.4.4) - ffi (1.15.4) - i18n (1.12.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + ast (2.4.3) + base64 (0.2.0) + benchmark (0.4.0) + bigdecimal (3.1.9) + concurrent-ruby (1.3.5) + connection_pool (2.5.0) + csv (3.3.3) + diff-lcs (1.6.0) + drb (2.2.1) + ffi (1.17.1) + ffi (1.17.1-aarch64-linux-gnu) + ffi (1.17.1-aarch64-linux-musl) + ffi (1.17.1-arm-linux-gnu) + ffi (1.17.1-arm-linux-musl) + ffi (1.17.1-arm64-darwin) + ffi (1.17.1-x86-linux-gnu) + ffi (1.17.1-x86-linux-musl) + ffi (1.17.1-x86_64-darwin) + ffi (1.17.1-x86_64-linux-gnu) + ffi (1.17.1-x86_64-linux-musl) + fileutils (1.7.3) + i18n (1.14.7) concurrent-ruby (~> 1.0) - language_server-protocol (3.16.0.3) - listen (3.7.0) + json (2.10.2) + language_server-protocol (3.17.0.4) + lint_roller (1.1.0) + listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - minitest (5.18.0) - parallel (1.21.0) - parser (3.0.3.0) + logger (1.6.6) + minitest (5.25.5) + mutex_m (0.3.0) + parallel (1.26.3) + parser (3.3.7.2) ast (~> 2.4.1) - rainbow (3.0.0) - rake (13.0.6) - rb-fsevent (0.11.0) - rb-inotify (0.10.1) + racc + racc (1.8.1) + rainbow (3.1.1) + rake (13.2.1) + rb-fsevent (0.11.2) + rb-inotify (0.11.1) ffi (~> 1.0) - rbs (1.7.1) - regexp_parser (2.1.1) - rexml (3.2.5) - rspec (3.10.0) - rspec-core (~> 3.10.0) - rspec-expectations (~> 3.10.0) - rspec-mocks (~> 3.10.0) - rspec-core (3.10.1) - rspec-support (~> 3.10.0) - rspec-expectations (3.10.1) + rbs (3.9.0) + logger + regexp_parser (2.10.0) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.3) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.3) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-mocks (3.10.2) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.2) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-support (3.10.3) - rubocop (1.23.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.2) + rubocop (1.74.0) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) parallel (~> 1.10) - parser (>= 3.0.0.0) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.12.0, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.38.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.13.0) - parser (>= 3.0.1.1) - rubocop-rake (0.6.0) - rubocop (~> 1.0) - rubocop-rspec (2.6.0) - rubocop (~> 1.19) - ruby-progressbar (1.11.0) - steep (0.46.0) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.41.0) + parser (>= 3.3.7.2) + rubocop-capybara (2.22.1) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-factory_bot (2.27.1) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-rake (0.7.1) + lint_roller (~> 1.1) + rubocop (>= 1.72.1) + rubocop-rspec (2.31.0) + rubocop (~> 1.40) + rubocop-capybara (~> 2.17) + rubocop-factory_bot (~> 2.22) + rubocop-rspec_rails (~> 2.28) + rubocop-rspec_rails (2.29.1) + rubocop (~> 1.61) + ruby-progressbar (1.13.0) + securerandom (0.4.1) + steep (1.10.0) activesupport (>= 5.1) - language_server-protocol (>= 3.15, < 4.0) + concurrent-ruby (>= 1.1.10) + csv (>= 3.0.9) + fileutils (>= 1.1.0) + json (>= 2.1.0) + language_server-protocol (>= 3.17.0.4, < 4.0) listen (~> 3.0) - parallel (>= 1.0.0) - parser (>= 3.0) + logger (>= 1.3.0) + mutex_m (>= 0.3.0) + parser (>= 3.1) rainbow (>= 2.2.2, < 4.0) - rbs (>= 1.2.0) - terminal-table (>= 2, < 4) - terminal-table (3.0.2) - unicode-display_width (>= 1.1.1, < 3) + rbs (~> 3.9) + securerandom (>= 0.1) + strscan (>= 1.0.0) + terminal-table (>= 2, < 5) + uri (>= 0.12.0) + strscan (3.1.2) + terminal-table (4.0.0) + unicode-display_width (>= 1.1.1, < 4) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicode-display_width (2.1.0) - yard (0.9.26) + unicode-display_width (3.1.4) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) + uri (1.0.3) + yard (0.9.37) PLATFORMS - x86_64-darwin-19 - x86_64-darwin-20 - x86_64-linux + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + ruby + x86-linux-gnu + x86-linux-musl + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl DEPENDENCIES bundler (~> 2.0) packageurl-ruby! rake (~> 13.0) rspec (~> 3.0) - rubocop (~> 1.23.0) - rubocop-rake (~> 0.6.0) - rubocop-rspec (~> 2.6.0) - steep (~> 0.46.0) + rubocop (~> 1.74) + rubocop-rake (~> 0.7) + rubocop-rspec (~> 2.19) + steep (~> 1.10.0) yard (~> 0.9.0) BUNDLED WITH - 2.2.32 + 2.6.6 diff --git a/lib/package_url.rb b/lib/package_url.rb index 11e5261..511cc86 100644 --- a/lib/package_url.rb +++ b/lib/package_url.rb @@ -72,7 +72,14 @@ def initialize(type:, name:, namespace: nil, version: nil, qualifiers: nil, subp # @raise [InvalidPackageURL] If the string is not a valid package URL. # @return [PackageURL] def self.parse(string) - components = {} + components = { + type: nil, + namespace: nil, + name: nil, + version: nil, + qualifiers: nil, + subpath: nil + } # Split the purl string once from right on '#' # - The left side is the remainder @@ -195,8 +202,16 @@ def self.parse(string) components[:namespace] = nil end - new(type: components[:type], - name: components[:name], + # Ensure type and name are not nil before creating the PackageURL instance + raise InvalidPackageURL, 'missing package type' if components[:type].nil? + raise InvalidPackageURL, 'missing package name' if components[:name].nil? + + # Create a new PackageURL with validated components + type = components[:type] || '' # This ensures type is never nil + name = components[:name] || '' # This ensures name is never nil + + new(type: type, + name: name, namespace: components[:namespace], version: components[:version], qualifiers: components[:qualifiers], diff --git a/packageurl-ruby.gemspec b/packageurl-ruby.gemspec index 539a860..9fda766 100644 --- a/packageurl-ruby.gemspec +++ b/packageurl-ruby.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |spec| DESCRIPTION spec.homepage = 'https://github.com/package-url/packageurl-ruby' - spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0') + spec.required_ruby_version = Gem::Requirement.new('>= 3.2.0') spec.license = 'MIT' spec.metadata['homepage_uri'] = spec.homepage diff --git a/sig/package_url.rbs b/sig/package_url.rbs index 99f51be..7c4a2f1 100644 --- a/sig/package_url.rbs +++ b/sig/package_url.rbs @@ -1,6 +1,9 @@ class PackageURL VERSION: String + class InvalidPackageURL < ArgumentError + end + def scheme: () -> String attr_reader type: String attr_reader namespace: String? @@ -9,32 +12,32 @@ class PackageURL attr_reader qualifiers: Hash[String, String]? attr_reader subpath: String? - def initialize: (type: String `type`, - ?namespace: String? namespace, - name: String name, - ?version: String? version, - ?qualifiers: Hash[String, String]? qualifiers, + def initialize: (type: String `type`, + ?namespace: String? namespace, + name: String name, + ?version: String? version, + ?qualifiers: Hash[String, String]? qualifiers, ?subpath: String? subpath) -> void - - def self.parse: (String string) -> PackageURL? - - def to_h: () -> { scheme: String, - type: String, - namespace: String?, - name: String?, - version: String?, - qualifiers: Hash[String, String]?, + + def self.parse: (String string) -> PackageURL + + def to_h: () -> { scheme: String, + type: String, + namespace: String?, + name: String?, + version: String?, + qualifiers: Hash[String, String]?, subpath: String? } def to_s: () -> String def deconstruct: () -> Array[String | Hash[String, String] | nil] - def deconstruct_keys: (Array[Symbol] keys) -> { scheme: String, - type: String, - namespace: String?, - name: String?, - version: String?, - qualifiers: Hash[String, String]?, + def deconstruct_keys: (Array[Symbol] keys) -> { scheme: String, + type: String, + namespace: String?, + name: String?, + version: String?, + qualifiers: Hash[String, String]?, subpath: String? } end