Hey,

Just joined the list, and I too have been thinking about a good path literal
for Perl 6. Nice to see so many other people are thinking the same :).

Not knowing where to start in this long thread, I will instead try to show how
I would like a path literal to work. For me a path literal is a way to make the
code pretty and clean. And for multi platform coding this is mostly where it
gets hard to do. So I think a path literal should make it possible to use both
a native style and a more modern portable one, without having to give up using
spaces like in Path::Spec from Perl 5 or have to do verbose object creation.

First I think extending Q with a Q:path{} and making the alias Q:p{} and p{}
would be the most consistent with the current string literal API. Also it
should be possible to sub type the literals to further limit format and
content. This should be done so we can get compile time error when path's are
know to be incorrect or that we throw an exception or return a undef with an
error type(or whatever Larry called it) when we interpolate and return
something that is known to be incorrect.

The default p{} should only allow "/" as separator and should not allow
characters that won't work on modern Windows and Unix like \ / ? % * : | " > <,
etc. The reason for this is that portable Path's should be the default and if
you really need platform specific behavior it should be shown in the code.

my Path $path = p{../ext/dictonary.txt};

or

my Path $path = p{c:/ext/dictonary.txt};

We should allow windows style paths so converting and maintaining code on this
platform is not a pain.

my Path $path = p:win{C:\Program Files\MS Access\file.file};

For Unix specific behavior we should have a p:unix{} literal, here the only
limit are what is defined by locale. So we won't be able to write full Unicode
if locale is set to Latin1. Writing filenames to the filesystem that other
programs won't be able to read should be hard.

my Path $path = p:unix{/usr/src/bla/myfile?:%.file};

And for people where this is a problem p:bin{} can be used as no checking is
done here.

my $path = p:bin{/usr/src/bla/??/adasd/myfile};

Old style Mac paths could also be supported where the : is used as separator.

my Path $path = p:mac{usr:src:bla};

Or old dos paths where 8 char limits and all the old dos stuff apply.

my Path $path = p:dos{c:\windows\test.fil};

Urls could also be support with:

my Path $path = p:url{file:///home/test.file}

** Path Object like File::Spec, etc. just nicer **

All the different variants for p{} return a Path object that offers much of
what is found in File::Spec, Cwd and Path::Class in Perl 5 today in a more
Perl 6 way.

my Path $real_path = $path.realpath; # Like Cwd's realpath

my Path $volume = $path.volume; # Returns the volume part if relevant
my Path $dir = $path.dir; # Returns the directory part
my Path $file = $path.file; # Returns the file part

$path.shift(); # Get rid of last part of path
$path.pop(); # Get rid of first part or path

my @paths = $path.dirs; # Returns the directory parts of the path

etc.

** Comparing Paths should do the right thing **

As we have the option of specifying what type a Path object is, this should
also count when comparing the them. So fx. p:win{} are case insensitive.

my $file = p:win{c:\My File.txt};

my $path = p:win{C:\Program Files\..};

if($path.is_in($file)) { # Check if the path is contained in another path
  say "$file is in $path\n"; # C:\My File.txt is C:
}

if(p{../test} ~~ p{../dir/../test}) {
  say "Comparing two Path works as it should";
}

Also Path handles Unicode normalization so this won't be a problem:

http://lists.zerezo.com/git/msg643117.html

Meaning that both "M<A WITH UMLAUT>rchen" and "Ma<UMLAUT MODIFIER>rchen" are
the same path, but without normalizing the path behind the users back.

** Utility functions **

Path in itself knows nothing about the filesystem and files but might have a
peek in $*CWD to do some path logic. Except for that a number of File related
functions might be available to make it easy to open and slurp a file a Path
points to.

my File $file = p{/etc/passwd}.open;
if($file.type ~~ 'text/plain') {
  say "looks like a password file";
}

my @passwd = p{/etc/passwd}.lines;


if(p{/etc/passwd}.exists) {
  say "passwd file exists";
}

This is my thought so far, hope it helps the discussion.

Regards Troels

Reply via email to