# Because Path is limited in form based on factors outside of it, it doesn't # actually provide any validation within itself. As such, this type is immutable # to prevent a problem. This could be made mutable if it is given a reference to # the parent URI class. The URI class is responsible for performing the # necessary validations. unit class URI::Path; use URI::Escape; has Str $.path; has @.segments; my @rules = < path-abempty path-absolute path-noscheme path-rootless path-empty >; multi method new(URI::Path:U: Match:D $comp, :$scheme) { my $path-type = @rules.first({ $comp{ $_ }.defined }); my $path = $comp{ $path-type }; my @segments := $path.list.grep(*.defined).map({.Str}).List || ('', ); if $path || $path -> $first-chunk { @segments := ($first-chunk.Str, |@segments); } if "$path".starts-with('/') { @segments := ('', |@segments); } $path = "$path"; if $scheme and $scheme ~~ /http/ { $path = $path.split("/").map( { uri-escape( uri-unescape($_) ) } ).join("/"); # Reconstruct path } self.new(:$path, :@segments); } submethod BUILD(:$!path = '', :@segments = $!path.split('/')) { @!segments := @segments.List; } multi method gist(URI::Path:D: --> Str ) { $!path } multi method Str(URI::Path:D: --> Str ) { $!path } method rel2abs(URI::Path:D: Str:D() $base) { if $!path.starts-with('/') { self; } else { my $path = $base.subst(rx{"/"*$}, '') ~ '/' ~ $!path; self.new: :$path; } }