=begin pod

=head1 NAME

PURL - Package URL specification v1.0.X

=head1 SYNOPSIS

=begin code :lang<raku>
use PURL;

my $purl := PURL.new("pkg:maven/org.apache.commons/io@1.3.4");
say $purl.type;       # maven
say $purl.namespace;  # org.apache.commons
say $purl.name;       # io
say $purl.version,    # 1.3.4

# Stringifies to the canonical version of the PURL
say $purl;  # pkg:maven/org.apache.commons/io@1.3.4

# If only interested in validity
if PURL("pkg:maven/org.apache.commons/io@1.3.4") {
    say "Valid Package URL";
}

# Create from an identity string
$purl = PURL.from-identity("PURL:auth<zef:lizmat>");

$purl = PURL.from-identity(
  "PURL:ver<0.0.5>:auth<zef:lizmat>"
  :must-be-pinned
);
=end code

=head1 DESCRIPTION

C<PURL> is distribution that provides a C<PURL> class that implements the
L<Package URL|https://github.com/package-url/purl-spec/blob/main/PURL-SPECIFICATION.rst>
specification, an attempt to standardize existing approaches to reliably
identify and locate software packages.

=head1 CHECKING VALIDITY

=begin code :lang<raku>
if PURL("pkg:maven/org.apache.commons/io@1.3.4") {
    say "Valid Package URL";
}
=end code

To just see whether a string that claims to be a Package URL is
valid, one can call the class itself with that string to check:
it will return either C<True> or C<False> (without throwing any
exception).

=head1 INSTANTIATION

An instantiated object will stringify in the canonical version of
the package URL.

=head2 new

=begin code :lang<raku>
my $purl := PURL.new("pkg:maven/org.apache.commons/io@1.3.4");
=end code

The C<PURL> object is instantiated with the C<.new> method and the
Package URL as the only positional argument.  It will throw an error
if there is some type of problem with the Package URL.

=begin code :lang<raku>
say PURL.new(:type<maven>, :name<io>, :version<3>);  # pkg:maven/io@3
=end code

It can also be instantiated in the ordinary named arguments way with
the C<.new> method.

=head2 from-identity

=begin code :lang<raku>
my $purl = PURL.from-identity("PURL:auth<zef:lizmat>");
=end code

Alternately a C<PURL> object can be instantiated from a Raku module
identity with the C<.from-identity> method.

=begin code :lang<raku>
my $purl = PURL.from-identity(
  "PURL:ver<0.0.5>:auth<zef:lizmat>"
  :must-be-pinned
);
=end code

If the PURL reference B<must> be referencing a specific version of a
distribution, then the C<:must-be-pinned> named argument can be
specified.  An error will be thrown if the specified identity is not
pinned in that case.

=head1 ACCESSORS

=head2 scheme

The scheme of the package specification: always 'pkg'.

=head2 type

The type of the package specification.

=head2 name

The name of the package specification.

=head2 namespace

The namespace of the package specification.

=head2 version

The version of the package specification.

=head2 qualifiers

The qualifiers of the package specification.

=head2 subpath

The subpath of tha package specification.

=head1 OTHER METHODS

=head2 VERS

=begin code :lang<raku>
my $purl = PURL.new("pkg:raku/zef:lizmat/PURL?vers=vers:raku/<2.0|>=1.0");
say $purl.VERS;  # vers:raku/>=1.10 | <2.0
=end code

Returns the associated C<VERS> object if there is any (as specified
by the "vers" qualifier key).  Returns C<Nil> if none found.

=head1 SUPPORTED TYPES

The C<PURL::Type> class allows for various types of introspection.

Calling the class with a string will either return the type object
for the given string, or a C<Failure>.

=begin code :lang<raku>
my $class = PURL::Type("bitbucket");
say "bitbucket is valid" unless $class ~~ Failure;
=end code

=head2 supported-names

=begin code :lang<raku>
say PURL::Type.supported-names;  # (alpm apk bitbucket bitnami...
=end code

The C<supported-names> class method returns the names of the supported
PURL types, in alphabetical order.

=head2 supported-types

=begin code :lang<raku>
say PURL::Type.supported-types;  # ((alpm) (apk) (bitbucket)...
=end code

The C<supported-types> class method returns the type objects of the
supported PURL types, in alphabetical order.

=head2 description

=begin code :lang<raku>
say PURL::Type.description("bitbucket");  # Bitbucket-based packages.
=end code

The C<description> class method takes the name of a PURL type and
returns its description.

=head2 examples

=begin code :lang<raku>
.say for PURL::Type.examples("bitbucket");  # pkg:bitbucket/birke...
=end code

The C<examples> class method takes the name of a PURL type and
returns a list of valid PURL examples of that PURL type.

=head1 AUTHOR

Elizabeth Mattijsen <liz@raku.rocks>

Source can be located at: https://github.com/lizmat/PURL . Comments
and Pull Requests are welcome.

If you like this module, or what I’m doing more generally, committing to a
L<small sponsorship|https://github.com/sponsors/lizmat/>  would mean a great
deal to me!

=head1 COPYRIGHT AND LICENSE

Copyright 2025, 2026 Elizabeth Mattijsen

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

=end pod

# vim: expandtab shiftwidth=4
