Module: Purl

Defined in:
lib/purl.rb,
lib/purl/errors.rb,
lib/purl/lookup.rb,
lib/purl/version.rb,
lib/purl/advisory.rb,
lib/purl/package_url.rb,
lib/purl/registry_url.rb,
lib/purl/lookup_formatter.rb,
lib/purl/advisory_formatter.rb

Overview

The main PURL (Package URL) module providing functionality to parse, validate, and generate package URLs according to the PURL specification.

A Package URL is a mostly universal standard to reference a software package in a uniform way across many tools, programming languages and ecosystems.

Examples:

Basic usage

purl = Purl.parse("pkg:gem/[email protected]")
puts purl.type     # "gem"
puts purl.name     # "rails"
puts purl.version  # "7.0.0"

Registry URL conversion

purl = Purl.from_registry_url("https://rubygems.org/gems/rails")
puts purl.to_s     # "pkg:gem/rails"

Package information lookup

purl = Purl.parse("pkg:cargo/[email protected]")
info = purl.lookup
puts info[:package][:description]
puts info[:version][:published_at] if info[:version]

See Also:

Defined Under Namespace

Classes: Advisory, AdvisoryError, AdvisoryFormatter, Error, InvalidNameError, InvalidNamespaceError, InvalidQualifierError, InvalidSchemeError, InvalidSubpathError, InvalidTypeError, InvalidVersionError, Lookup, LookupError, LookupFormatter, MalformedUrlError, MissingRegistryInfoError, PackageURL, ParseError, RegistryError, RegistryURL, UnsupportedTypeError, ValidationError

Constant Summary collapse

KNOWN_TYPES =

Known PURL types loaded from JSON configuration

load_types_config["types"].keys.sort.freeze
InvalidPackageURL =
Deprecated.

Use ParseError instead

Legacy compatibility - matches packageurl-ruby’s exception name

ParseError
VERSION =
"1.6.0"

Class Method Summary collapse

Class Method Details

.all_type_infoHash<String, Hash>

Get comprehensive information about all types

Examples:

all_info = Purl.all_type_info
gem_info = all_info["gem"]

Returns:

  • (Hash<String, Hash>)

    hash mapping type names to their information

See Also:

  • for structure of individual type information


155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/purl.rb', line 155

def self.all_type_info
  result = {}
  
  # Start with known types
  KNOWN_TYPES.each do |type|
    result[type] = type_info(type)
  end
  
  # Add any registry-supported types not in known list
  RegistryURL.supported_types.each do |type|
    unless result.key?(type)
      result[type] = type_info(type)
    end
  end
  
  result
end

.default_registry(type) ⇒ String?

Get default registry URL for a type

Examples:

registry = Purl.default_registry("gem")
puts registry  # "https://rubygems.org"

Parameters:

  • type (String, Symbol)

    the type to get default registry for

Returns:

  • (String, nil)

    default registry URL or nil if not available



233
234
235
236
237
238
# File 'lib/purl.rb', line 233

def self.default_registry(type)
  config = type_config(type)
  return nil unless config
  
  config["default_registry"]
end

.from_registry_url(registry_url, type: nil) ⇒ Object

Convenience method for parsing registry URLs back to PURLs

Parameters:

  • registry_url (String)

    The registry URL to parse

  • type (String, Symbol, nil) (defaults to: nil)

    Optional type hint for custom domains



68
69
70
# File 'lib/purl.rb', line 68

def self.from_registry_url(registry_url, type: nil)
  RegistryURL.from_url(registry_url, type: type)
end

.known_type?(type) ⇒ Boolean

Check if a type is known/valid

Examples:

Purl.known_type?("gem")     # true
Purl.known_type?("unknown") # false

Parameters:

  • type (String, Symbol)

    the type to check

Returns:

  • (Boolean)

    true if type is known, false otherwise



113
114
115
# File 'lib/purl.rb', line 113

def self.known_type?(type)
  KNOWN_TYPES.include?(type.to_s.downcase)
end

.known_typesArray<String>

Returns all known PURL types

Examples:

types = Purl.known_types
puts types.include?("gem")  # true

Returns:

  • (Array<String>)

    sorted array of known PURL type names



79
80
81
# File 'lib/purl.rb', line 79

def self.known_types
  KNOWN_TYPES.dup
end

.load_types_configObject

Load PURL types configuration from JSON file



40
41
42
43
44
45
46
# File 'lib/purl.rb', line 40

def self.load_types_config
  @types_config ||= begin
    config_path = File.join(__dir__, "..", "purl-types.json")
    require "json"
    JSON.parse(File.read(config_path))
  end
end

.parse(purl_string) ⇒ PackageURL

Convenience method for parsing PURL strings

Examples:

purl = Purl.parse("pkg:gem/[email protected]")
puts purl.name  # "rails"

Parameters:

  • purl_string (String)

    a PURL string starting with “pkg:”

Returns:

Raises:



61
62
63
# File 'lib/purl.rb', line 61

def self.parse(purl_string)
  PackageURL.parse(purl_string)
end

.registry_config(type) ⇒ Hash?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get registry configuration for a type

Parameters:

  • type (String, Symbol)

    the type to get registry config for

Returns:

  • (Hash, nil)

    registry configuration hash or nil if not available



218
219
220
221
222
223
# File 'lib/purl.rb', line 218

def self.registry_config(type)
  config = type_config(type)
  return nil unless config
  
  config["registry_config"]
end

.registry_supported_typesArray<String>

Returns types that have registry URL support

Examples:

types = Purl.registry_supported_types
puts types.include?("npm")  # true if npm has registry support

Returns:

  • (Array<String>)

    sorted array of types that can generate registry URLs



90
91
92
# File 'lib/purl.rb', line 90

def self.registry_supported_types
  RegistryURL.supported_types
end

.reverse_parsing_supported_typesArray<String>

Returns types that support reverse parsing from registry URLs

Examples:

types = Purl.reverse_parsing_supported_types
puts types.include?("gem")  # true if gem has reverse parsing support

Returns:

  • (Array<String>)

    sorted array of types that can parse registry URLs back to PURLs



101
102
103
# File 'lib/purl.rb', line 101

def self.reverse_parsing_supported_types
  RegistryURL.supported_reverse_types
end

.type_config(type) ⇒ Hash?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get type configuration from JSON

Parameters:

  • type (String, Symbol)

    the type to get configuration for

Returns:

  • (Hash, nil)

    configuration hash or nil if type not found



178
179
180
181
182
183
# File 'lib/purl.rb', line 178

def self.type_config(type)
  config = load_types_config["types"][type.to_s.downcase]
  return nil unless config
  
  config.dup # Return a copy to prevent modification
end

.type_description(type) ⇒ String?

Get human-readable description for a type

Examples:

desc = Purl.type_description("gem")
puts desc  # "Ruby gems from RubyGems.org"

Parameters:

  • type (String, Symbol)

    the type to get description for

Returns:

  • (String, nil)

    description string or nil if not available



193
194
195
196
# File 'lib/purl.rb', line 193

def self.type_description(type)
  config = type_config(type)
  config ? config["description"] : nil
end

.type_examples(type) ⇒ Array<String>

Get example PURLs for a type

Examples:

examples = Purl.type_examples("gem")
puts examples.first  # "pkg:gem/[email protected]"

Parameters:

  • type (String, Symbol)

    the type to get examples for

Returns:

  • (Array<String>)

    array of example PURL strings



206
207
208
209
210
211
# File 'lib/purl.rb', line 206

def self.type_examples(type)
  config = type_config(type)
  return [] unless config
  
  config["examples"] || []
end

.type_info(type) ⇒ Hash

Get comprehensive type information including registry support

Examples:

info = Purl.type_info("gem")
puts info[:description]  # "Ruby gems from RubyGems.org"

Parameters:

  • type (String, Symbol)

    the type to get information for

Returns:

  • (Hash)

    hash containing type information with keys:

    • :type: normalized type name

    • :known: whether type is known

    • :description: human-readable description

    • :default_registry: default registry URL

    • :examples: array of example PURLs

    • :registry_url_generation: whether registry URL generation is supported

    • :reverse_parsing: whether reverse parsing is supported

    • :route_patterns: array of URL patterns for this type



133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/purl.rb', line 133

def self.type_info(type)
  normalized_type = type.to_s.downcase
  {
    type: normalized_type,
    known: known_type?(normalized_type),
    description: type_description(normalized_type),
    default_registry: default_registry(normalized_type),
    examples: type_examples(normalized_type),
    registry_url_generation: RegistryURL.supports?(normalized_type),
    reverse_parsing: RegistryURL.supported_reverse_types.include?(normalized_type),
    route_patterns: RegistryURL.route_patterns_for(normalized_type)
  }
end

.types_config_metadataHash

Get metadata about the types configuration

Examples:

 = Purl.
puts "Total types: #{[:total_types]}"

Returns:

  • (Hash)

    metadata hash with keys:

    • :version: configuration version

    • :description: configuration description

    • :source: source of the configuration

    • :last_updated: when configuration was last updated

    • :total_types: total number of types

    • :registry_supported_types: number of types with registry support

    • :types_with_default_registry: number of types with default registry



254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/purl.rb', line 254

def self.
  config = load_types_config
  {
    version: config["version"],
    description: config["description"],
    source: config["source"],
    last_updated: config["last_updated"],
    total_types: config["types"].keys.length,
    registry_supported_types: config["types"].select { |_, v| v["registry_config"] }.keys.length,
    types_with_default_registry: config["types"].select { |_, v| v["default_registry"] }.keys.length
  }
end