=encoding utf8

=head1 TITLE

Synopsis 32: Setting Library - IO

=head1 VERSION

    Created: 19 Feb 2009

    Last Modified: 28 Oct 2014
    Version: 27

=head1 Overview

This synopsis describes in depth the subroutines and methods that were
described broadly in S16.  Please note that any implementation is free
to use multi-method dispatch on both subroutines as well as methods should
this increase the performance or maintainability.

=head1 Functions

=head2 print()
X<print()>

    sub print(*@text --> Bool) is export

Print the given text on C<$*OUT>.

=head2 say()
X<say()>

    sub say(*@text --> Bool) is export

Print the given text, followed by a new line C<"\n"> on C<$*OUT>.  Before
printing, call the C<.gist> method on any non-C<Str> objects.

=head2 note()
X<note()>

    sub note(*@text --> Bool) is export

Print the given text, followed by a new line C<"\n"> on C<$*ERR>.  Before
printing, call the C<.gist> method on any non-C<Str> objects.

=head2 dd()
X<dd()>

    sub dd(@vars --> Bool) is export

Tiny Data Dumper.  Takes the C<variables> specified and C<note>s them (on
C<$*ERR>) in an easy to read format, along with the C<name> of the variable.
So:

  my $a = 42;
  dd($a);   # notes "$a = 42"

=head2 prompt()
X<prompt()>

    sub prompt($msg --> Bool) is export

Simple Prompter.  Print message on C<$*OUT> and obtains a single line of
input from C<$*IN>.

=head2 open()
X<open()>

    sub open ($name as IO,
      # mode
        Bool :$r  = True,
        Bool :$w  = False,
        Bool :$rw = False,
        Bool :$a  = False,
      # encoding
        Bool :$bin = False,
        Str  :$enc = "Unicode",  # utf-8 unless otherwise
      # newlines
        Any  :$nl    = "EOL",
        Bool :$chomp = True,
        --> IO::Handle ) is export

A convenience function for opening normal files as text (by default) as
specified by its (first) parameter.  It returns an instantiated L</IO::Handle>
object.  The following named parameters may also be specified:

=over 4

=item :r

Open file for reading.  Default is C<True>.

=item :w

Open file for writing by creating an empty file with the given name.  The
original contents of an existing file with that name, will be B<lost>.
Default is C<False>.

=item :rw

Open file for reading and writing with the given name.  The original contents
of an existing file with that name, will be B<lost>.  Default is C<False>.

=item :a

Open file for appending, create one if it didn't exist yet.  This may or may
not inhibit overwriting the original contents when moving the file pointer.
Default is C<False>.

=item :bin

Open file in binary mode (byte mode).  A file opened with C<:bin> may still be
processed line-by-line, but IO will be in terms of C<Buf> rather than C<Str>
types.  Default is C<False>, implying text semantics.

=item :enc

Encoding to use if opened in text mode.  Defaults to "Unicode", which
implies figuring out which actual UTF is
in use, either from a BOM or other heuristics.  If heuristics are
inconclusive, UTF-8 will be assumed.  (No 8-bit encoding will ever
be picked implicitly.)

=item :nl

The marker used to indicate the end of a line of text.  Only used in text
mode.  Defaults to "EOL", which implies accepting any combination of C<"\n">,
C<"\r\n"> or C<"\r"> or any other Unicode character that has the C<Zl>
(Separator, Line) property.

=item :chomp

Whether or not to remove new line characters from text obtained with
C<.lines> and C<.get>.  Defaults to C<True>.

=back

=head2 dir()
X<dir()>

    sub dir($directory as Str = $*CWD,
        Mu       :$test = $*SPEC.curupdir,
        Bool     :$absolute = False,
        Bool     :$Str = False,
        IO::Path :$CWD = $*CWD,
        --> List ) is export

Returns a lazy list of (relative) paths in the C<$directory> as C<IO::Path>
objects, by default from the directory pointed to by C<$*CWD>.  If dir() fails,
it returns an L<X::IO::Dir|S32::Exception/X::IO::Dir> failure.  The following
named parameters are optional:

=over 4

=item :test

Expression against which to smart-match for inclusion in result list.  By
default excludes C<curdir> (usually ".") and C<updir> (usually "..") only.

=item :absolute

Boolean indicating to return absolute path names, rather than relative ones.
False by default.

=item :Str

Boolean indicating to return C<Str>ings, rather than C<IO::Path> objects.
False by default.

=item :CWD

Only important if C<:absolute> is specified with a True value.  The directory
to pre-pend to the relative file paths.  Defaults to C<$*CWD>.

=back

=head2 slurp()
X<slurp()>

    sub slurp ($what = $*ARGFILES,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        --> Str|Buf ) is export

Slurps the contents of the entire file into a C<Str> (or C<Buf> if C<:bin>).
Accepts C<:bin> and C<:enc> optional named parameters, with the same meaning
as L</open()>.  The routine will C<fail> if the file does not exist, or is a
directory.

=head2 spurt()
X<spurt()>

    sub spurt ($where, $what,
        Str  :$enc        = $*ENC,
        Bool :append      = False,
        Bool :$createonly = False,
        --> Bool ) is export

Writes the indicated contents (2nd positional parameter) to the location
indicated by the first positional parameter (which can either be a string,
an C<IO::Path> object, or an already opened C<IO::Handle> object).

If a file needs to be opened for writing, it will also be C<close>d.  Returns
True on success, or the appropriate C<Failure> if something went wrong.

These named parameters are optional and only have meaning if the first
positional parameter was B<not> an C<IO::Handle>:

=over 4

=item :enc

The encoding with which the contents will be written. [conjectural]

=item :append

Boolean indicating whether to append to a (potentially) existing file.  If
the file did not exist yet, it will be created.  Defaults to C<False>.

=item :createonly

Boolean indicating whether to fail if the file already exists.  Defaults to
C<False>.

=back

=head2 mkdir()
X<mkdir()>

    sub mkdir($dir as IO, $mode = 0o777 --> Bool) is export

Creates the directory as indicated by the positional parameter.  Returns
C<True> on success or an appropriate C<Failure>.

=head2 rmdir()
X<rmdir()>

    sub rmdir($dir as IO --> Bool) is export

Removes the (empty) directory as indicated by the positional parameter.
Returns C<True> on success or an appropriate C<Failure>.

=head2 chdir()
X<chdir()>

    sub chdir($dir as IO, $CWD = $*CWD,
        :$test = <d r>
        --> Bool) is export

Changes the current working directory to the given directory, for the scope in
which C<$*CWD> is active (if no second positional parameter is given) or for
the scope of the indicated localized C<$*CWD>.  A typical use case:

  {
      chdir("foo", my $*CWD);
      # working directory changed to "foo"
  }
  # restored to what it was

Returns C<True> if successful, or an appropriate C<Failure>, e.g if the
directory does not exist, or is not a directory, or is not readable.

Please note that this directory has B<no> connection with whatever the
operating system thinks is the current working directory.  The value of
C<$*CWD> just will always be prepended to any relative paths in any file
operation in Perl 6.

Also note that you can use C<chdir> to set similar dynamic variables, like
C<$*TMPDIR> and C<$*HOME> this way:

  chdir("bar", my $*TMPDIR);   # set $*TMPDIR in this scope
  chdir("bar", my $*HOME);     # set $*HOME in this scope

=head2 copy()
X<copy()>

    sub copy ($source as IO, $dest as IO,
        :$createonly = False,
        --> Bool ) is export

Copies a file, as indicated by the first positional parameter, to the
destination specified.  If :createonly is set to True, copy fails if a file
already exists in the destination.  Returns C<True> upon success, or an
appropriate C<Failure> if the operation could not be completed.

=head2 rename()
X<rename()>

    sub rename ($source as IO, $dest as IO,
        :$createonly = False,
        --> Bool ) is export

Moves a file, as indicated by the first positional parameter, by renaming it
to the destination specified.  If :createonly is set to True, the rename fails
if a file already exists in the destination.  Returns C<True> upon success, or
an appropriate C<Failure> if the operation could not be completed.

Please use L</move()> if a file could not be moved by renaming (usually because
the destination is on a different physical storage device).

=head2 move()
X<move()>

    sub move ($source as IO, $dest as IO,
        :$createonly = False,
        --> Bool ) is export

Moves a file, as indicated by the first positional parameter, by copying its
contents to the destination specified, and then removing the file at the
original location.  If :createonly is set to True, the move fails if a file
already exists in the destination.  Returns C<True> upon success, or an
appropriate C<Failure> if the operation could not be completed.

Please use L</rename()> if a file can be moved by renaming (which is usually
possible if the destination is on the same different physical storage device).
Alternately, the C<move()> function is free to try the C<rename()> first,
and if that (silently) fails, do it the hard way.

=head2 unlink()
X<unlink()>

    sub unlink(*@files --> @removed) is export

Delete all specified ordinary files, links, or symbolic links.  Returns the
names of the files that were successfully deleted.

=head3 chmod()
X<chmod()>

    sub chmod($permission, *@files --> @changed) is export

Changes the permissions of a list of files.  The first element of the
list must be the numerical mode, which should probably be an octal
number, and which definitely should I<not> be a string of octal digits:
C<0o644> is okay, C<0644> is not.  Returns the names of the files that were
successfully changed.

    $count = chmod 0o755, 'foo', 'bar';
    chmod 0o755, @executables;
    $mode =  '0644'; chmod $mode, 'foo';  # BAD!!! sets mode to --w----r-T
    $mode = '0o644'; chmod $mode, 'foo';  # this is better
    $mode =  0o644 ; chmod $mode, 'foo';  # this is best

=head2 link()
X<link()>

    sub link($target, $source --> Bool) is export

Create a hard link between the target from the given source path.  Returns
C<True> if successful, or an appropriate C<Failure>.

=head2 symlink()
X<symlink()>

    sub symlink($target, $source --> Bool) is export

Create a symbolic link between the target from the given source path.  Returns
C<True> if successful, or an appropriate C<Failure>.

=head1 IO Types

=head2 IO

    role IO { };

The base role only tags that this is an C<IO> object for more generic
purposes. It doesn't specify any methods or attributes.

=head2 IO::Spec

This class is a collection of methods dealing with file specifications
(commonly known as file names, though it can include the entire directory path).
Most of the methods allow access to lower-level operations on file path strings.

These operations are significantly different on some operating systems, so the
actual work is being done by subclasses such as C<IO::Spec::Unix>,
C<IO::Spec::Win32> and C<IO::Spec::Cygwin>.

The correct C<IO::Spec> class for your system, is available in the C<$*SPEC>
dynamic variable.  So typically, you would call methods on that:

  my $cleanpath = $*SPEC.canonpath("a/.//b/")  # gives "a/b"

This set of modules was inspired by Perl 5's C<File::Spec>.  An implementation
may choose to inherit from C<IO::Spec>, or any of its subclasses, if that
helps in avoiding code duplication.

The C<select> method is the only method provided by C<IO::Spec> itself.

=head3 .select
X<.select>

    method select(IO::Spec:U: $name = $*DISTRO.name as Str --> IO::Spec:U)

The C<.select> method takes an optional argument: a string indicating the
type of system for which to perform file specification operations.  By
default, it takes C<$*DISTRO.name>.

At startup, C<$*SPEC> is initialized to C<IO::Spec.select>.

=head2 IO::Spec subclasses

The following methods should be provided by the C<IO::Spec> subclasses, or
may be inherited from another class.  They will never check anything with
an actual file system.  In alphabetical order:

=head3 .abs2rel
X<.abs2rel>

    method abs2rel($path as Str, $base = $*CWD --> Str)

Takes a path and an optional base path (default C<$*CWD>) and returns a
relative path from the base path to the destination path.  If the base path
is relative, then it will first be transformed to an absolute path with
L</.rel2abs>, relative to C<$*CWD>.

On systems with the concept of volume, if C<$path> and C<$base> appear to be
on two different volumes, it will not attempt to resolve the two paths, and
will instead simply return C<$path>.

On systems that have a grammar that indicates filenames, this ignores the
C<$base> filename as well. Otherwise all path components are assumed to be
directories.

If C<$path> is relative, it is first converted to absolute form using
L</.rel2abs>.  This means that it is taken to be relative to C<$*CWD>.

=head3 .canonpath
X<.canonpath>

    method canonpath($path as Str --> Str)

Perform a logical cleanup of a path and returns that.  Note that this does
*not* collapse F<x/../y> sections into F<y>.  This is by design.  If F</foo>
on your system is a symlink to F</bar/baz>, then F</foo/../quux> is actually
F</bar/quux>, not F</quux> as a naive F<../>-removal would give you.  If you
want to do this kind of processing, you probably want L</IO::Path>'s
L</.resolve> method to actually traverse the filesystem cleaning up paths
like this.

=head3 .catdir
X<.catdir>

    method catdir(*@dir as Array[Str] --> Str)

Concatenate two or more directory names to form a complete path ending
with a directory.  Removes any trailing slashes from the resulting
string, unless the result is the L</.rootdir>.

=head3 .catpath
X<.catpath>

    method catpath($volume, $dir, $file --> Str)

Takes volume, directory and file portions and returns an entire path string.
Under Unix, C<$volume> is ignored, and directory and file are concatenated.
On other OSes, C<$volume> is significant.  Directory separators like slashes
are inserted if need be.

=head3 .contents
X<.contents>

=head3 .curdir
X<.curdir>

    method curdir(--> Str)

Returns a string representation of the current directory (Usually C<".">).

=head3 curupdir

Returns a test as to whether a given path is identical to the current
directory (as indicated by L</.curdir>) or the parent directory (as indicated
by L</.updir>.  This is usually C<< none(<. ..>) >>.  It is the default for
the C<:test> parameter to C</dir()> and L</IO::Path>'s L</.contents> method.
It can also be used to extend C<dir()> through its C<:test> named parameter:

  dir "my/directory", test => all($*SPEC.curupdir, /^ '.' /);

This example would return all files beginning with a period that are
not C<"."> or C<".."> directories.

=head3 .devnull
X<.devnull>

    method devnull(--> Str)

Returns a string representation of the null device (e.g. C<"/dev/null"> on
Unix-like systems).

=head3 .extension
X<.extension>

    method extension($path as Str --> Str)

Returns the extension (if any) of the given path.

=head3 .is-absolute
X<.is-absolute>

    method is-absolute($path as Str --> Bool)

Takes as its argument a path, and returns C<True> if it is an absolute path,
C<False> otherwise.  For C<IO::Spec::Win32>, it returns 1 if it's an absolute
path without a volume, and 2 if it's absolute with a volume.

=head3 .join
X<.join>

    method join(:$volume, $dir, $file --> Str)

A close relative of L</.catpath>, this method takes volume, directory and
basename portions and returns an entire path string.  If a directory is B<".">,
it is removed from the (relative) path output, because this function inverts
the functionality of dirname and basename.

Directory separators are inserted if necessary.  Under Unix, $volume is
ignored, and only directory and basename are concatenated.  On other OSes,
$volume is significant.

This method is the inverse of L</.split>; the results can be passed to it
to get the volume, dirname, and basename portions back.

=head3 .PATH
X<.PATH>

    method PATH($PATH = %*ENV<PATH> --> List[Str])

Convert a string formatted like a system's C<PATH> specification, and returns
it as a list of strings.  Takes C<< %*ENVE<lt>PATHE<gt> >> by default.

=head3 .rel2abs
X<.rel2abs>

    method rel2abs($path as Str, $base = $*CWD as Str --> Str)

Converts a relative path to an absolute path, using an optional base directory.
If the base directory is not specified, C<$*CWD> will be assumed.

If C<$base> is relative, then it is first converted to absolute form, relative
to C<$*CWD>.

On systems with the concept of volume, if C<$path> and C<$base> appear to be
on two different volumes, t will not attempt to resolve the two paths, and
will instead simply return C<$path>.

On systems that have a grammar that indicates filenames (like VMS), this
ignores the C<$base> specification as well. Otherwise all path components are
assumed to be directories.

If C<$path> is absolute, it is cleaned up and returned using L</.canonpath>.

=head3 .rootdir
X<.rootdir>

    method rootdir(--> Str)

Returns a string representation of the root directory (usually C<"/">).

=head3 .split
X<.split>

    method split($path as Str --> Hash[Str])

A close relative of L</.splitdir>, this function also splits a path into
volume, directory, and basename portions.  Unlike L</.splitdir>, split returns
paths compatible with dirname and basename I<and> returns it arguments as
a hash of C<volume>, C<directory>, and C<basename>.

This means that trailing slashes will be eliminated from the directory
and basename components, in Win32 and Unix-like environments.  The basename
component will always contain the last part of the path, even if it is a
directory, C<'.'>, or C<'..'>.  If a relative path's directory portion would
otherwise be empty, the directory is set to whatever C<curdir> is.

On systems with no concept of volume, returns C<''> (the empty string) for
volume.  The results can be passed to L</.join> to get back a path equivalent
to (but not necessarily identical to) the original path.  If you want to keep
all of the characters involved, use L</.splitdir> instead.

=head3 .splitdir
X<.splitdir>

    method splitdir($directories as Str --> List[Str])

The opposite of L</.catdir>.  C<$directories> must be only the directory
portion of the path on systems that have the concept of a volume or that have
path syntax that differentiates files from directories.

Unlike just splitting the directories on the separator, empty directory names
(C<''>) can be returned, because these are significant on some OSes.

=head3 .splitpath
X<.splitpath>

    method splitpath( $path, $nofile = False )

Splits a path in to volume, directory, and filename portions and returns these
as a List. On systems with no concept of volume, returns '' for volume.

    my ($volume,$directories,$file) = $*SPEC.splitpath( $path );
    my ($volume,$directories,$file) = $*SPEC.splitpath( $path, $no_file );

For systems with no syntax differentiating filenames from directories,
assumes that the last file is a path unless C<$no_file> is C<True> or a
trailing separator or F</.> or F</..> is present. On Unix, this means that
C<$no_file> true makes this return ( '', $path, '' ).

The directory portion may or may not be returned with a trailing '/'.

The results can be passed to L</.catpath> to get back a path equivalent to
(but not necessarily identical to) the original path.

=head3 .tmpdir
X<.tmpdir>

    method tmpdir(--> IO::Path)

Returns an L</IO::Path> representation of the first writable directory from an
implicit list of possible temporary directories.  Returns the current directory
if no writable temporary directories are found.  The list of directories
checked depends on the platform.

=head3 .updir
X<.updir>

    method updir(--> Str)

Returns a string representation of the parent directory (usually C<"..">).

=head3 Comparison of .splitpath and .split

    OS      Path       splitpath               split
    Unix    /a/b/c     ("", "/a/b/", "c")      ("", "/a/b", "c")
    Unix    /a/b//c/   ("", "/a/b//c/", "")    ("", "/a/b", "c")
    Unix    /a/b/.     ("", "/a/b/.", "")      ("", "/a/b", ".")
    Win32   C:\a\b\    ("C:", "\\a\\b\\", "")  ("C:", "\\a", "b")
    VMS     A:[b.c]    ("A:", "[b.c]", "")     ("A:", "[b]", "[c]")

* The VMS section is still speculative, and not yet supported.

=head3 Comparison of .catpath and .join

    OS     Components            catpath        join
    Unix   ("", "/a/b", "c")     /a/b/c         /a/b/c
    Unix   ("", ".", "foo")      ./foo          foo
    Unix   ("", "/", "/")        //             /
    Win32  ("C:", "\a", "b")     C:\a\b         C:\a\b
    VMS    ("A:", "[b]", "[c]")  A:[b][c]       A:[b.c]

* The VMS section is still speculative, and not yet supported.

=head2 IO::Path

    class IO::Path is Cool { }

Holds a path of a file or directory. The path is generally divided
into three parts, the I<volume>, I<dirname> and I<base name>.

On Windows, the volume is a drive letter like C<C:>, or a UNC network volume
like C<\\share\>. On UNIX-based systems, the volume part is empty.

The basename is name of the file or directory that the C<IO::Path> object
represents, and the directory is the part of the path leading up to the
basename.

    path              volume         dirname    basename
    /usr/bin/gvim                    /usr/bin   gvim
    /usr/bin/                        /usr       bin
    foo/bar.txt                      foo        bar.txt
    C:\temp\f.txt     C:             \temp      f.txt
    \\server\share\a  \\server\share \          a

By default, C<IO::Path> uses the C<IO::Spec> setting as found in C<$*SPEC>
when the object is created.  If you want to work paths as if you were using
another OS, you can specify another C<IO::Spec> subclass with the optional
C<:SPEC> named parameter.

There are several ways of creating an C<IO::Path>.  The easiest way is to use
C<.IO> coercer:

  my $io = "foo/bar".IO;

Of course, you can always call the C<.new> method as well:

  my $io = IO::Path.new( $full-path );
  my $io = IO::Path.new( :$volume, :$dirname, :$basename);

Whenever a new C<IO::Path> is created, an internal absolute and cleaned version
of the specified path is stored, using the implicitly or explicitly
specified values for C<$*SPEC> and C<$*CWD>:

  my $io = IO::Path.new( "foo", :SPEC<win32>, :CWD</usr/local/src> );

would create an C<IO::Path> object with C<IO::Spec::Win32> semantics, with an
absolute path of C</usr/local/src/foo>.  Yes, that would be strange, but it
B<is> possible.  A shorter way would be:

  my $io = "foo".IO( :SPEC<win32>, :CWD</usr/local/src> );

The (implicit) value of C<:CWD> is only used for creating the absolute path
at instantiation time.  The (implicit) value of C<:SPEC> is actually saved
in the object to be able to perform path operations with the correct semantics
at a later time.

=head3 File test methods

The following (single letter) methods can be used on the C<IO::Path> object:

    M  Test performed                              Returns
    =  ==============                              =======
    r  Path is readable by effective uid/gid.      Bool
    w  Path is writable by effective uid/gid.      Bool
    x  Path is executable by effective uid/gid.    Bool
    o  Path is owned by effective uid.             Bool

    R  Path is readable by real uid/gid.           Bool
    W  Path is writable by real uid/gid.           Bool
    X  Path is executable by real uid/gid.         Bool
    O  Path is owned by real uid.                  Bool

    e  Path exists.                                Bool
    s  Size of the path in bytes.                  Int
    z  Path has zero size (an empty file).         Bool

    f  Path is a plain file.                       Bool
    d  Path is a directory.                        Bool
    l  Path is a symbolic link.                    Bool
    L  Actual path of symbolic link (readlink)     Str
    p  Path is a named pipe (FIFO)                 Bool
    S  Path is a socket.                           Bool
    b  Path is a block special file.               Bool
    c  Path is a character special file.           Bool

    u  Path has setuid bit set.                    Bool
    g  Path has setgid bit set.                    Bool
    k  Path has sticky bit set.                    Bool

To allow for easy chaining of file tests, there is an C<.all> method that can
be fed the tests to be tried as a C<List> of strings.  The value returned
will be the first non-True value, or the final True value.

  say "rwx" if $io.all: <r w x>;

  if $io.all(<f r w x s>) -> $size {
      say "plain file with rwx of $size bytes";
  }

For convenience, you can also specify the negated letter for the opposite test:

  if $io.all(<!d r w x s>) -> $size {
      say "not a directory with rwx of $size bytes";
  }

Other methods are listed here in alphabetical order:

=head3 .absolute
X<.absolute>

    method absolute($base as Str --> Str)

The absolute path of the path, optionally from the relative base.

=head3 .accessed
X<.accessed>

    method accessed(--> Instant)

Returns the C<Instant> when the file was last accessed, or C<Failure> if
this could not be determined.

=head3 .basename
X<.basename>

    method basename(--> Str)

Returns the base name part of the path -- that is, the last portion.  Functions
equivalently to the C<basename> shell program on Unix-like systems.

=head3 .changed
X<.changed>

    method changed(--> Instant)

Returns the C<Instant> when the metadata of the file was last changed, or
C<Failure> if this could not be determined.

=head3 .chdir
X<.chdir>

    method chdir(:$CWD = $*CWD --> Bool)

Like L</chdir()>, but with L</.absolute> as the first parameter.

=head3 .child
X<.child>

    method child($childname --> IO::Path)

Appends C<$childname> to the end of the path, adding path separators where
needed and returns the result as a new C<IO::Path>.

=head3 .chmod
X<.chmod>

    method chmod($permissions --> Bool)

Like L</chmod()>, but with L</.absolute> as the second parameter.

=head3 .copy
X<.copy>

    method copy($dest, :$createonly --> Bool)

Like L</copy()>, but with L</.absolute> as the first parameter.

=head3 .dir
X<.dir>

    method dir(:$test, :$absolute, :$CWD --> List[Str])

Like L</dir()>, but with L</.absolute> as the first parameter.

=head3 .dirname
X<.dirname>

    method dirname(-->Str)

Returns the directory part of the path, not including the last item.  Functions
equivalently to the C<dirname> shell program on Unix-like systems.

=head3 .extension
X<.extension>

    method extension(--> Str)

Returns the extension of the path, if any.

=head3 .IO
X<.IO>

    method IO(--> IO::Path)

Returns itself.

=head3 .is-absolute
X<.is-absolute>

    method is-absolute(--> Bool)

Always returns C<True> since internally the path is always stored as an
absolute path.

=head3 .is-relative
X<.is-relative>

    method is-relative(--> Bool)

Always returns C<False> since internally the path is always stored as an
absolute path.

=head3 .lines
X<.lines>

    method lines( --> List[Str] )

Returns a (lazy) list of lines of which the file consists, or a C<Failure>
if something went wrong.

=head3 .mkdir
X<.mkdir>

    method mkdir($mode = 0o777 --> Bool)

Like L</mkdir()>, but with L</.absolute> as the first parameter.

=head3 .modified
X<.modified>

    method modified(--> Instant)

Returns the C<Instant> when the contents of the file were last modified, or
C<Failure> if this could not be determined.

=head3 .move
X<.move>

    method move($dest as IO, :$createonly --> Bool)

Like L</move()>, but with L</.absolute> as the first parameter.

=head3 .open
X<.open>

    method open(... --> IO::Handle)

Like L</open()>, but with L</.absolute> as the first parameter.

=head3 .parent
X<.parent>

    method parent(--> IO::Path)

Removes last portion of the path and returns the result as a new C<IO::Path>.

=head3 .pred
X<.pred>

    method pred(--> IO::Path)

Create previous logical path and return the result as a new C<IO::Path> or
returns C<Failure> if that is not possible.

=head3 .relative
X<.relative>

    method relative ($base as Str = $*CWD --> IO::Path)

Transforms the path into an relative form, and returns the result as a new
C<IO::Path>.  If C<$base> is supplied, transforms it relative to that base
directory, otherwise the C<$*CWD>is used.  Paths that are already relative
are returned unchanged.

=head3 .rename
X<.rename>

    method rename($dest as IO, :$createonly --> Bool)

Like L</rename()>, but with L</.absolute> as the first parameter.

=head3 .resolve
X<.resolve>

    method resolve(--> IO::Path)

Returns a new IO::Path object with all symbolic links and references to the
parent directory (C<..>) are physically resolved.  This means that the
filesystem is examined for each directory in the path, and any symlinks found
are followed.

  # bar is a symlink pointing to "/baz"
  my $io = "foo/./bar/..".IO.resolve;  # now "/" (the parent of "/baz")

=head3 .rmdir

    method rmdir(--> Bool)

Removes (deletes) the directory represented by the C<IO::Path>.  Returns
C<True> if successful, or a C<Failure> of some kind if not.  Typically fails
if the path is not a directory or the directory is not empty.

=head3 .slurp
X<.slurp>

    method slurp(:$bin, :$enc  --> Str|Buf)

Like L</slurp()>, but with L</.absolute> as the first parameter.

=head3 .SPEC
X<.SPEC>

    method SPEC(--> IO::Spec)

Returns the L</IO::Spec> object that was (implicitely) specified at object
creation time.

=head3 .spurt
X<.spurt>

    method spurt(:$enc, :$append, :$createonly, :$bin  --> Str|Buf)

Like L</spurt()>, but with L</.absolute> as the first parameter.

=head3 .succ
X<.succ>

    method succ(--> IO::Path)

Create next logical path and return the result as a new C<IO::Path>.

=head3 .unlink

    method unlink(--> Bool)

Like L</unlink()>, but with L</.absolute> as the first parameter.
Returns C<True> on success or an appropriate C<Failure>.

=head3 .volume
X<.volume>

    method volume(-->Str)

Returns the volume part of the path.  On Unix-like OSes or systems without a
concept of volume in the path, returns the empty string.

=head3 .words
X<.words>

    method words( :$nw = "WS" --> List[Str] )

Returns a (lazy) list of words of which the file consists, or a C<Failure>
if something went wrong.  Also takes the following optional named parameters:

=over 4

=item :nw

The delimiter between what are to be considered words.  By default assumes
C<"WS">, which indicates any whitespace character.

=back

=head3 Subclasses

The C<IO::Path> class may have C<IO::Spec> specific subclasses.  But basically,
these would only implicitely specify the C<IO::Class> to be specified for
the C<.new> method:

  class IO::Path::Win32 {
      method new(|c) { IO::Path.new(|c, :SPEC(IO::Spec::Win32) }
  }

=head2 IO::Handle

    class IO::Handle does IO { ... }

A handle of a file, pipe or anything else that supports reading or
writing like a file.

The C<IO::Handle> object is usually B<not> directly instantiated, but with
L</open()> or L</IO::Path>'sL</.open>.  Nonetheless, you B<can> create an
C<IO::Handle> object with just a path:

  my $handle = IO::Handle.new($filename as Str);
  my $handle = IO::Handle.new($filename as Str, :SPEC(*$SPEC));
  my $handle = IO::Handle.new($filename as Str, :SPEC(*$SPEC), :CWD($*CWD));

This does not interact with anything at all and will appear as if the file
has been C<.close>d.  From then on, the C<.path> method will return the
C<IO::Path> object that was created

The C<.open> method B<does> interact with the file system:

  $handle.open;  # same as $handle = $filename.IO.open

It has the same optional named parameters as L</open()> and either returns
B<itself> (for historical reasons), or a C<Failure> with additional information.

=head3 Methods handled by .path

The filename specified with C<.new> is internally stored as an L</IO::Path>
object, obtainable with the C<.path> method.  The following methods are handled
by C<.path> and work exactly the same:

  absolute       the absolute, canonical path
  accessed       last access time (if available)
  basename       the basename of the path
  changed        last (metadata) changed time
  chmod          change attributes of path
  dirname        the directory part of the absolute path
  extension      the extension of the file
  is-absolute    is the (original) path absolute
  is-relative    is the (original) path relative
  modified       last modified time
  relative       the relative path against CWD
  SPEC           the :SPEC at instantiation time
  volume         the volume of the path (if any)

The following methods also work the same as with C<IO::Path>, but it may be
less logical to use these on an C<IO::Handle> object as these return new
C<IO::Path> objects.

  child          append basename to path
  IO             same as .path
  parent         remove last portion of path
  pred           previous logical path
  resolve        follow symlinks to the real path
  succ           next logical path

These C<IO::Path> methods seem to only make sense if the C<IO::Handle> object
is closed.  But there may be some uses for this, but it seems more like extra
rope for shooting yourself in the foot.

  copy           create a copy of file
  mkdir          create directory
  move           move (rename) to other storage
  rename         rename (move) to other name
  rmdir          remove directory if empty directory
  unlink         remove file

[Conjecture: perhaps the above methods should fail on IO::Handle]

Contrary to the C<IO::Path> methods with the same name, these methods operate
only from the current file position.  If the file was just opened, it's
identical as with the C<IO::Path> version.  But if you have done anything
to the handle that moved the file pointer, you will get a different result.

  lines          contents of file as lines
  slurp          obtain the contents of the file
  spurt          write / append contents to file
  words          contents of file as words

The other methods of C<IO::Handle> are:

=head3 .close
X<.close>

    method close(--> Bool)

Closes the handle and returns C<True>, or a C<Failure> if something went wrong.

=head3 .encoding
X<.encoding>

    method encoding(--> Str)

    method encoding($encoding --> Str)

Without arguments, simply returns the current encoding used on the handle.
If supplied with a string identifying a valid encoding, change the handle
to read with that encoding from then on.  Options include C<binary>, C<utf8>,
and other text encodings.  An invalid encoding causes the method to return
a C<Failure>.

=head3 .eof
X<.eof>

    method eof(--> Bool)

Returns C<True> if the handle is exhausted, C<False> otherwise.

=head3 .fileno
X<.fileno>

    method fileno(--> int)

Returns the file descriptor, which is always a native integer, conforming to
C89.

=head3 .flush
X</flush>

    method flush(--> Bool)

Attempts to flush any buffered data, returns C<True> if successful, an
appropriate C<Failure> otherwise.

=head3 .get
X<.get>

    method get(--> Str)

Reads the next line and returns it.  Uses the (implicit) specification of
C<:nl> with L</open> to determine where a line ends.  Returns a C<Str> type
object if no more lines to be read.

=head3 .getc
X<.getc>

    method getc(Int $chars = 1 --> Str)

Tries to read C<$chars> characters and return them concatenated as a string.
Returns a C<Str> type object if no more lines to be read.

=head3 .ins
X<.ins>

    method ins(--> Int)

Returns the number of lines that have been read with L</.get> or L</.lines>.

=head3 .opened
X<.opened>

    method opened(--> Bool)

Return whether the file is opened.

=head3 .p
X<.p>

    method p(--> Bool)

Returns whether the handle is opened to a pipe.

=head3 .print
X<.print>

    method print (*@text --> Bool)

Stringifies each element, concatenates those strings, and writes the
result to the file.  Returns C<True> if successful, a C<Failure> otherwise.

=head3 .read
X<.read>

    method read(Int $bytes --> Buf)

Reads and returns C<$bytes> bytes from the handle, or as many as are possible.

=head3 .say
X<.say>

    method say (*@text --> Bool)

This is identical to L</.print> except that it stringifies its arguments by
calling C<.gist> on them and auto-appends a newline after the final argument.

=head3 .seek
X<.seek>

    method seek(Int $position, MoveMethod $whence --> Bool)

Move the file pointer to C<$position>. The meaning of this position is
always in "bytes", so you better know what you're doing in a text-file.

The C<$whence> value should be a C<MoveMethod> value, which is one of:

    name        value
    =========== =====
    FromStart     0
    FromCurrent   1
    FromEnd       2

These numerical values will also be accepted.  Returns C<True> on success,
or a C<Failure> if something went wrong (e.g. when using C<$*IN> on a terminal
input).

=head3 .t
X<.t>

    method t(--> Bool)

Returns C<True> if the handle is opened to a tty, aka there might actually
be a person watching.

=head3 .tell
X<.tell>

    method tell(--> Int)

Returns the position of the file pointer in "bytes".

=head3  .write
X<.write>

    method write(Buf $buf --> Int)

Tries to write C<$buf> to the file. The actual number of bytes written is
returned, or a C<Failure> if something went wrong.

=over

This is "raw" write. C<$buf> contains plain bytes. If you want to C<write>
a C<Str>, you should C<.encode> it first, or use L</.print>.

=back

=head1 Here Be Dragons

Everything below this point hasn't been reviewed properly

=head2 IO::Socket

    role IO::Socket {
        has %.options;
        has Bool $.Listener;
        ...
    }

Accessing the C<%.options> would on Unix be done with I<getsockopt(2)>/I<setsockopt(2)>.

The $.Listener attribute indicates whether the socket will be a listening socket when
opened, rather than indicating whether it is currently listening.

=over

=item new

    method new(
        :$Listener, # initializes $.Listener
    )

The initial value of the $.Listener attribute is defined according to the following rules:

 * If $Listener is passed to .new(), then that value is used
 * If neither a local address nor a remote address are passed in, throw an exception
 * If no remote address is passed, then $.Listener is set to SOMAXCONN
 * If no local address is used, then $Listener is set to 0
 * If both local and remote addresses are used, throw an exception that asks people to
   specify $Listener

=item open

    method open()

If $.Listener is true, does a I<bind(2)> and a I<listen(2)>, otherwise does a
I<connect(2)>.

It's end-user use case is intended for the case where NoOpen is passed to .new().  .new()
itself will presumably also call it.

=item close

    method close()

Implements the close() function from IO::Closeable by doing a shutdown on the connection
(see below) with @how set to ('Readable', 'Writeable').

=item shutdown

    method shutdown(Str @how)

Does a I<shutdown(2)> on the connection.  See also IO::Readable.isReadable and
IO::Writeable.isWriteable.

$how can contain 1 or more of the strings 'Readable' and 'Writeable'.

=item accept

    method accept( --> IO::Socket)

=item method read(Int $bytes --> Buf)

Reads and returns C<$bytes> bytes from the handle

=item method write(Buf $buf --> Int)

Implements the IO::Writeable interface by doing  a I<send(2)>.

=back

=head2 IO::Socket::INET

    class IO::Socket::INET does IO::Socket {
        has Str $.proto = 'TCP';
        has Str $.host;
        has Int $.port;
        has Str $.localhost;
        has Int $.localport;
        ...
    }

=over

=item new

    multi method new(:$host!, :$port, *%attributes) { ... }
    multi method new(:$localhost!, :$localport, :$listen! *%attributes) { ... }

Creates a new socket and opens it.

=back

=head1 Conjectural Stuff

Everything below this point should be considered as mere ideas for
future evolution, not as things that a compiler write should implement
unquestioningly.

=head2 IO::ACL

This is a basic abstraction; for better control, use the operating-system specific
interfaces, over which this is a thin veneer.

    class IO::ACL {
        has Str $.type; # "User", "Group", "Everyone", ???
        has Str $.id; # username or groupname; unused for $type eq "Everyone"
        has %.permissions;
                # Unsupported values may (or may not) throw
                # UnsupportedPermission when set or read
        has Path $.owningObject;
        ...
    }

The permissions used in C<%permissions> are:

=over

=item Readable

Should be supported by all filesystems as an item to read from the hash for the group
"Everyone".

=item Writeable

Should be supported by all filesystems as an item to read from the hash for the group
"Everyone".

=item Executable

Supported on most Unix systems, anyway.  Windows should be able to guess when this is
read, and throw an exception if written to.

=item Default

An ACL of User,fred,Default sets the user "fred" to be the owner of the file.  This can be
done with groups too.  Works on Unix, at least.

=back

The C<$.owningObject> attribute of C<ACL> shows what the ACL is set on.  On a
Windows system, this can be a parent directory, as permissions are inherited.


=head2 IO::Pipe

    class IO::Pipe does IO::Streamable does IO::Readable does IO::Writable {
        ...
    }

Will need to set IO::Readable.isReadable and IO::Writable.isWriteable depending on opening
method.

=over

=item close()

If the file handle came from a piped open, C<close> will additionally
return C<Failure> (aliased to C<$!>) if one of the other system calls involved fails, or if the
program exits with non-zero status.  The exception object will contain any
pertinent information.  Closing a pipe
also waits for the process executing on the pipe to complete, in case you
want to look at the output of the pipe afterwards, and
implicitly puts the exit status value into the C<Failure> object if necessary.

=item IO::Pipe.to

    method to(Str $command, *%opts --> Bool)
    method to(Str *@command, *%opts --> Bool)

Opens a one-way pipe writing to C<$command>.  C<IO> redirection for
stderr is specified with C<:err(IO)> or C<< :err<Str> >>.  Other C<IO> redirection
is done with feed operators. XXX how to specify "2>&1"?

=item IO::Pipe.from

    method from(Str $command, *%opts --> Bool)
    method from(Str *@command, *%opts --> Bool)

Opens a one-way pipe reading from $command.  C<IO> redirection for
stderr is specified with C<:err(IO)> or C<< :err<Str> >>.  Other C<IO> redirection
is done with feed operators. XXX how to specify "2>&1"?

=item IO::Pipe.pair

    method pair(--> List of IO::Pipe)

A wrapper for I<pipe(2)>, returns a pair of C<IO> objects representing the
reader and writer ends of the pipe.

   ($r, $w) = IO::Pipe.pair;

=back

=head2 OS-specific classes

=head3 Unix

=head3 Path::Unix

=over

=item chown

    multi chown ($uid = -1, $gid = -1, *@files --> Int)

Changes the owner (and group) of a list of files.  The first
two elements of the list must be the numeric uid and gid, in
that order.  A value of -1 in either position is interpreted by
most systems to leave that value unchanged.  Returns the number
of files successfully changed.

    $count = chown $uid, $gid, 'foo', 'bar';
    chown $uid, $gid, @filenames;

On systems that support C<fchown>, you might pass file handles
among the files.  On systems that don't support C<fchown>, passing
file handles produces a fatal error at run time.

Here's an example that looks up nonnumeric uids in the passwd
file:

   $user = prompt "User: ";
   $pattern = prompt "Files: ";

   ($login,$pass,$uid,$gid) = getpwnam($user)
       or die "$user not in passwd file";

   @ary = glob($pattern);      # expand filenames
   chown $uid, $gid, @ary;

On most systems, you are not allowed to change the ownership of
the file unless you're the superuser, although you should be
able to change the group to any of your secondary groups.  On
insecure systems, these restrictions may be relaxed, but this
is not a portable assumption.  On POSIX systems, you can detect
this condition this way:

    use POSIX qw(sysconf _PC_CHOWN_RESTRICTED);
    $can-chown-giveaway = not sysconf(_PC_CHOWN_RESTRICTED);

=item stat

=item IO.stat

    $node.stat(Bool :$link); # :link does an lstat instead

Returns a stat buffer.  If the lstat succeeds, the stat buffer evaluates
to true, and additional file tests may be performed on the value.  If
the stat fails, all subsequent tests on the stat buffer also evaluate
to false.

=back

=head3 IO::Socket::Unix

    role IO::Socket::Unix does IO::Socket {
        has Str $.RemoteAddr, # Remote Address
        has Str $.LocalAddr,  # Local Address
    }

=over

=item new

    method new(
        Str  :$RemoteAddr,
        Str  :$LocalAddr,

        Bool :$Listener,   # Passed to IO::Socket.new()

        Bool :$Blocking,   # Passed to IO::Streamable.new()
        Bool :$NoOpen,     # Passed to IO::Streamable.new()

        --> IO::Socket::Unix
    ) {...}

=item pair

    method pair(Int $domain, Int $type, Int $protocol --> List of IO)

A wrapper for I<socketpair(2)>, returns a pair of C<IO> objects representing the
reader and writer ends of the socket.

   use IO::Socket;
   ($r, $w) = IO::Socket::Unix.pair(AF_UNIX, SOCK_STREAM, PF_UNSPEC);


=back


=head3 IO::POSIX

Indicates that this object can perform standard posix C<IO>
operations. It implies C<IO::Readable> and C<IO::Writeable>.

=over

=item method dup( --> IO)

=item has Bool $.blocking is rw

=item method flock(:$r,:$w --> Bool)

=item method funlock( --> Bool)

=item ...

=back

=head1 Unfilled

=over 4

=item IO.ioctl

Available only as a handle method.

=item alarm

=item prompt

    multi prompt (Str $prompt --> Str)

Should there be an IO::Interactive role?

=item Str.readpipe

=item sysopen

=item IO.sysseek

=item umask

=back

=head1 Removed functions

=over

=item IO.eof

Gone, see eoi C<IO::Seekable>.

=item IO.fileno

See C<IO::Handle>.

=item /(get|set)(host|net|proto|serv|sock).*/

Should be implemented by an external library.

=item lstat

Use C<stat> with the C<:link> option.

=item IO.name

Changed to C<.path>, but we haven't gotten around to specifying this on all of them.

The C<.name> method returns the name of the file/socket/uri the handle
was opened with, if known.  Returns Nil otherwise.  There is no
corresponding C<name()> function.

=item pipe

Gone, see Pipe.pair

=item select(both)

Gone.  (Note: for sub-second sleep, just use sleep with a fractional argument.)

=item IO.shutdown()

Gone, see C<IO::Socket.close()>, C<$IO::Readable.isReadable>, and C<$IO::Writeable.isWriteable>

=item socketpair

Gone, see Socket.pair

=item IO.sysread

Gone, see C<IO::Readable.read()>.

=item IO.syswrite

Gone, see C<IO::Writeable.read()>.

=item utime

Gone, see C<Path.times>.

=back

=head2 IO::Buffered

Indicates that this object performs buffering. The management of the
buffer is completely implementation specific.

=over

=item method autoflush( --> Bool) is rw

Forces this object to keep its buffers empty

If set to nonzero, forces a flush right away and after every write
or print on the currently selected output channel.
Default is 0 (regardless of whether the channel is really buffered
by the system or not;
C<$OUT_FH.autoflush> tells you only whether you've asked Perl
explicitly to flush after each write).
C<$*OUT> will typically be line buffered if output is to the
terminal and block buffered otherwise.
Setting this variable is useful primarily when you are
outputting to a pipe or socket,
such as when you are running a Perl program under rsh
and want to see the output as it's happening.
This has no effect on input buffering.


=back

=head2 IO::Streamable

This role represents objects that depend on some external resource,
which means that data might not be available at request.

    role IO::Streamable does IO {...}

=over

=item new()

    method new(
        Bool :$NoOpen,
        Bool :$Blocking,
        --> IO::Streamable
    ) {...}

Unless the NoOpen option is passed, an open will be done on the C<IO> object when it is
created.

If blocking is passed in, .blocking() is called (see below).

=item method blocking( --> Bool) is rw

This allows the user to control whether this object should do a
blocking wait or immediately return in the case of not having data
available.

=item uri

    method uri(Str $uri --> IO::Streamable) {...}

This should be callable on the class, and act like a kind of "new()" function.  When given
a URI, it returns an C<IO::Streamable> of the appropriate type, and throws an error when an
inappropriate type is passed in.  For example, calling C<IO::File.uri('http://....')> will
throw an error (but will suggest using just uri('http://...') instead).

=back

=head2 IO::Encoded

This is a generic role for encoded data streams.

=over

=item method encoding( --> Str) is rw

=item method locale( --> Str) is rw

Encoding and locale are required for sane conversions.

=back

=head2 IO::Readable::Encoded

This role provides encoded access to a readable data stream, implies
C<IO::Encoded>. Might imply C<IO::Buffered>, but that's not a requirement.

=over 4

=item uri
X<uri>X<ftp>X<http>

    method uri(Str $uri --> IO::Streamable);
    sub uri(Str $uri --> IO::Streamable);

Returns an appropriate C<IO::Streamable> descendant, with the type depending on the uri
passed in.  Here are some example mappings:

    URI type IO type
    ======== =======
    file:    IO::Path
    ftp:     IO::Socket::INET (data channel)
    http:    IO::Socket::INET

These can naturally be overridden or added to by other modules.

=item %*PROTOCOLS dynamic variable

For each protocol, stores a type name that should be instantiated by calling the C<uri>
constructor on that type, and passing in the appropriate uri.

=back

=head1 AUTHORS

    The authors of the related Perl 5 docs
    Rod Adams <rod@rodadams.net>
    Larry Wall
    Aaron Sherman <ajs@ajs.com>
    Mark Stosberg <mark@summersault.com>
    Carl Mäsak <cmasak@gmail.com>
    Moritz Lenz <moritz@faui2k3.org>
    Tim Nelson <wayland@wayland.id.au>
    Daniel Ruoso <daniel@ruoso.com>
    Lyle Hopkins <webmaster@cosmicperl.com>
    Brent Laabs <bslaabs@gmail.com>
    Tobias Leich <email@froggs.de>
    Elizabeth Mattijsen <liz@wenzperl.nl>

=for vim:set expandtab sw=4: