This page was generated by Text::SmartLinks v0.01 at 2015-05-31 10:00:08 GMT.
(syn df6900d)
  [ Index of Synopses ]

=encoding utf8

TITLE

DRAFT: Synopsis 32: Setting Library - IO

VERSION

    Created: 19 Feb 2009 extracted from S29-functions.pod; added stuff from S16-IO later
    Last Modified: 05 May 2014
    Version: 23

The document is a draft.

Overview

The most common IO operations are print and say for writing and lines and get for reading. All four are available as subroutines (defaulting to the $*OUT and $*ARGFILES file handles) and as methods on file handles.

File handles are of type IO::Handle, and can be created with &open. Paths are generally passed as strings or IO::Path objects.

&dir returns IO::Path objects.

              default handle
    routine   for sub form    purpose
    =======   ===========     =======
    print     $*OUT           string-based writing
    say       $*OUT           string-based writing
    get       $*ARGFILES      read a line (Str)
    lines     $*ARGFILES      read all lines (Str)
    read                      binary reading (Buf)
    write                     binary writing (Buf)

File tests are performed through IO::Path objects.

Functions

open
    multi open (Str $name,
      # mode
        Bool :$r  = True,
        Bool :$w  = False,
        Bool :$rw = False,
        Bool :$a  = False,
      # encoding
        Bool :$bin = False,
        Str  :$enc = "Unicode",
      # newlines
        Any  :$nl = "\n",
        Bool :$chomp = True,
        ...
        --> IO::Handle
    ) is export

A convenience function that hides most of the OO complexity. It will only open normal files. Text is the default. Note that the "Unicode" encoding 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.) A file opened with :bin may still be processed line-by-line, but IO will be in terms of Buf rather than Str types.

For a discussion of the read/write/append modes (:r, :w, :a), see "IO::Handle/open" under IO::Handle.

dir
    multi dir($directory = '.', Mu :$test = none('.', '..')) { ... }

Returns a lazy list of file names in the $directory. By default the current and the parent directory are excluded, which can be controlled with the $test named parameter. Only items that smart-match against this test are returned.

The return value is a list of IO::Path objects. Because of this, you may want use the basename method on the results to get the just the file name, without its full path. If dir() fails, it returns an X::IO::Dir failure.

glob
    multi glob(Str $pattern --> Array[Str])

Accepts a pattern that will then be expanded into a array of filenames (the creation of IO objects from this list is left to the user).

The default glob function operates on POSIX rules, which may be read in more detail in the glob(7) manpage, however an overview is presented below.

The glob function understands a few metacharacters:

    \    Escape metacharacter
    ~    Home directory
    ?    Match exactly one character
    *    Match zero or more characters
    [    Start of character class (ends with ])

Note that this is not a regex-like syntax, so the ? and * are not quantifiers.

    glob("foo?");  # roughly equivalent to /^ foo. $/, NOT /^ foo? $/
    glob("*bar");  # valid syntax; roughly equivalent to /^ .* bar $/

The character class construct [...] matches all characters specified. It has a few metacharacters of its own:

    glob("[]]");     # matches the ] character
    glob("[!abc]");  # matches all but 'a', 'b', or 'c' (negation)
    glob("[a-z]");   # matches all lowercase letters from a to z (range)
    glob("[a-]");    # matches 'a' and '-'
    glob("[[:xdigit:]]"); # matches hexadecimal digit (named character class)

Ranges matches all the characters that fall between and the startpoint and endpoint, inclusively. Note that the / character can never be matched by a range. If contained within the a range (such as [--0]), the / is skipped. If explicitly specified as the start- or endpoint, it's considered a syntax error.

    glob("[--0]");   # matches '-', '.', or '0' (skips '/')
    glob("[a/b]");   # matches 'a', '/', or 'b'
    glob("[/-0]");   # syntax error

There are some notable departures from POSIX in terms of what the Perl 6 &glob function allows with character classes. Namely, neither the [[.ch.]] nor [[=ch=]] forms are supported, and the [^...] form is not undefined, but rather matches the ^ character among other things.

Glob metacharacters that must be escaped outside character classes aren't within.

    glob('\[\*\?\~');    # Matches the filename "[*?~"
    glob("[[*?~]");      # Matches the filenames "[", "*", "?", and "~"

Unlike Perl 5, no special attention is given to the interpolation rules of strings, particularly braces.

note
    multi note (*@LIST --> Bool)

Does a "say" to $*ERR, more or less. Like warn, it adds a newline only if the message does not already end in newline. Unlike warn, it is not trappable as a resumable exception because it outputs directly to $*ERR. You can suppress notes in a lexical scope by declaring:

    only note(*@) {}
slurp
    multi slurp (IO::Handle $fh = $*ARGFILES,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        --> Str|Buf
    )
    multi slurp (Str $filename,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        --> Str|Buf
    )

Slurps the entire file into a Str (or Buf if :bin) regardless of context. (See also lines.)

The routine will fail if the file does not exist, or is a directory.

spurt
    multi spurt (IO::Handle $fh,
        Str   $contents,
        Str  :$enc = $?ENC,
        Bool :append = False,
        Bool :$createonly = False,
    )
    multi spurt (IO::Handle $fh,
        Buf   $contents,
        Bool :append = False,
        Bool :$createonly = False,
    )
    multi spurt (Str $filename,
        Str   $contents,
        Str  :$enc = $?ENC,
        Bool :append = False,
        Bool :$createonly = False,
    )
    multi spurt (Str $filename,
        Buf   $contents,
        Bool :append = False,
        Bool :$createonly = False,
    )

Opens the file for writing, dumps the contents, and closes the file.

This routine will fail if the file exists and :createonly is set.

If :append is provided, an existing file will not be clobbered, but the string will be appended.

The routine will also fail with the corresponding exception if there was any other error in opening, writing, or closing.

chdir
    multi sub chdir(Str:D)
    multi sub chdir(IO::Path:D)

Changes the current (emulated) working directory to the new value, scoped to the current scope of $*CWD (usually thread-local at worst, or the scope of a visitdir inside the current thread). Fails (X::IO::Chdir) on error. If $*CWD is not scoped to the current dynamic scope, you must call chdir again when exiting the dynamic scope to get back to the original directly, just as you would with a real chdir. In this case you would probably be better off using visitdir instead, which will automatically scope $*CWD to the current dynamic scope.

Note that actually changing the process's working directory requires a call to PROCESS::chdir (which will inform the chdir emulation that the process's actual current working directory has changed). This function is not threadsafe, however. And if calling out to a foreign function, only one thread can safely use it; in general it's better to pass absolute paths to foreign functions that don't allow you to set the working directory as a parameter.

visitdir
    multi sub visitdir(Str:D)
    multi sub visitdir(IO::Path:D)

Changes the current (emulated) working directory to the new value, scoped to the current dynamic scope just as temp $*CWD = newdir(); would. Fails (X::IO::Chdir) on error. Since $*CWD is dynamically scoped, leaving the current dynamic scope automatically restores the current (emulated) working directory.

unlink
    sub unlink(Cool:D $path)

Unlinks an ordinary file, link, or symbolic link from disk -- that is, it is deleted. Returns True on success; otherwise returns an "X::IO::Unlink" in S32::Exception failure.

rmdir
    sub rmdir(Cool:D $directory)

Removes the directory given from disk. Returns True on success, or an X::IO::Rmdir failure.

mkdir
    sub mkdir(Cool:D $directory)

Makes (creates) the directory represented by the IO::Path. Returns True on success, or an X::IO::Mkdir failure.

IO Types

IO

    role IO { };

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

IO::Handle

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

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

open
    multi method open (
      # mode
        Bool :$r  = True,
        Bool :$w  = False,
        Bool :$rw = False,
        Bool :$a  = False,
      # encoding
        Bool :$bin = False,
        Str  :$enc = "Unicode",
      # newlines
        Any  :$nl = "\n",
        Bool :$chomp = True,
        --> IO::Handle
    ) is export

Open the handle for reading or writing (or both). Specifying :r, the default, opens the handle as read-only, :w is write-only, :rw is read-write, and :a appends writes to the file.

The :enc parameter controls which text encoding the file is interpreted as. Unicode is the default encoding. See "encoding" for encoding options.

The :nl option sets "input-line-separator", and :chomp determines if the new line separator will be chopped removed by get and lines.

Conjectural: The <:p> parameter opens a pipe, which is readable with :r (default) and writable with :w.

get
    method get() returns Str:D

Reads and returns one line from the handle. Uses input-line-separator to determine where a line ends.

lines
    method lines($limit = Inf)

Returns a lazy list of lines read via the get method, limited to $limit lines.

getc
    method getc (IO::Handle:D: Int $chars = 1 --> Str)

Reads $chars and returns them

print
    method print (IO::Handle:D: *@LIST --> Bool)
    multi print (*@LIST --> Bool)

Stringifies each element, concatenates those strings, and sends the result to the output. Returns Bool::True if successful, Failure otherwise.

The compiler will warn you if use a bare sub print without arguments. (However, it's fine if you have an explicit argument list that evaluates to the empty list at runtime.)

    print;             # warns
    if $_ { print }    # warns
    if $_ { print() }  # ok, but does nothing
    if $_ { print () } # ok, but does nothing
say
    method say (IO::Handle:D: *@LIST --> Bool)
    multi say (*@LIST --> Bool)

This is identical to print() except that it stringifies its arguments by calling .gist on them and auto-appends a newline after the final argument.

    Was:    print "Hello, world!\n";
    Now:    say   "Hello, world!";

As with print, the compiler will warn you if you use a bare sub say without arguments.

printf
    method printf (Str $fmt, *@LIST --> Bool)
    multi printf (IO::Handle:D: Str $fmt, *@LIST --> Bool)

Output through Str.sprintf. See S32::Str for details.

write
    method write(IO::Handle:D: Buf $buf --> Int)

Tries to write $buf. The actual number of bytes written is returned. It might return unthrown failures, to be specified by each IO implementation.

This is "raw" write. $buf contains plain octets. If you want to write a Str, you should .encode it first, or use "print" or other IO::Writeable::Encoded methods.

slurp
    method slurp(
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        --> Str|Buf)

Opens the handle if necessary, slurps the entire file into a Str (or Buf if :bin parameter is given) regardless of context. Closes the handle after it is done, and returns the contents of the file. (See also "lines".)

The routine will fail if the file does not exist, or is a directory.

spurt
    multi method spurt (
        Str   $contents,
        Str  :$enc = $?ENC,
        Bool :append = False,
        Bool :$createonly = False)
    multi method spurt (
        Buf   $contents,
        Bool :append = False,
        Bool :$createonly = False)

Opens the file for writing, dumps the contents, and closes the file.

This routine will fail if the file exists and :createonly is set.

If :append is provided, an existing file will not be clobbered, but the string will be appended.

The routine will also fail with the corresponding exception if there was any other error in opening, writing, or closing.

t
    method t() returns Bool:D

Returns True if the handle is opened to a tty.

p
    method p() returns Bool:D

Returns True if the handle is opened to a pipe.

eof
    method eof() returns Bool:D

Returns True if the handle is exhausted.

seek

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

Position this stream into $position. The meaning of this position is always in "octets".

Fails if the handle is not seekable.

TODO: make $whence an Enum

tell
    method tell() returns Int:D:

Returns the current raw position in the stream in number of "octets".

ins
    method ins( --> Int)

Returns the number of lines that have been read with get.

input-line-separator
    method input-line-separator( --> Str) is rw

This regulates how get and lines behave.

The input line (record) separator, newline by default. This influences Perl's idea of what a ``line'' is. Works like awk's RS variable, including treating empty lines as a terminator if set to the null string. (An empty line cannot contain any spaces or tabs.) You may set it to a multi-character string to match a multi-character terminator, or to Nil to read through the end of file. Setting it to "\n\n" means something slightly different than setting to "", if the file contains consecutive empty lines. Setting to "" will treat two or more consecutive empty lines as a single empty line. Setting to "\n\n" will blindly assume that the next input character belongs to the next paragraph, even if it's a newline.

You may also set it to a regular expression. The value of $/ will be (temporarily) set to the matched separator upon input, if you care about the contents of the separator.

encoding
    multi method encoding($enc?)

With no arguments, simply returns the current encoding used on the handle. If supplied a string identifying a valid encoding, change the handle to read with that encoding. Options include binary, utf8, and other text encodings. An invalid encoding causes the method to fail.

IO

Returns the handle itself (no-op).

close

Closes the handle. Fails on error.

IO::FileTestable

    role IO::FileTestable does IO { ... }

Provides ways to inspect a file or path without opening it.

If you apply that role to a class, that class must provide a Str method which returns the full path. IO::FileTestable will call this method to obtain the path to test. Stringification must return Str:D here.

The methods are typically only one letter long (for now; Perl 5 tradition strikes) and are summarized in the following table:

    M  Test performed                              Returns
    =  ==============                              =======
    r  Path is readable by effective uid/gid.      Bool:D
    w  Path is writable by effective uid/gid.      Bool:D
    x  Path is executable by effective uid/gid.    Bool:D
    o  Path is owned by effective uid.             Bool:D
    R  Path is readable by real uid/gid.           Bool:D
    W  Path is writable by real uid/gid.           Bool:D
    X  Path is executable by real uid/gid.         Bool:D
    O  Path is owned by real uid.                  Bool:D
    e  Path exists.                                Bool:D
    s  Size of the path in bytes.                  Int:D
    z  Path has zero size (an empty file).         Bool:D
    f  Path is a plain file.                       Bool:D
    d  Path is a directory.                        Bool:D
    l  Path is a symbolic link.                    Bool:D
    p  Path is a named pipe (FIFO)                 Bool:D
    S  Path is a socket.                           Bool:D
    b  Path is a block special file.               Bool:D
    c  Path is a character special file.           Bool:D
    u  Path has setuid bit set.                    Bool:D
    g  Path has setgid bit set.                    Bool:D
    k  Path has sticky bit set.                    Bool:D

All methods (except for e) return the appropriate type object if a path has been specified that does not exist.

accessed

Returns the last access time (atime) of the path, to the degree that it is updated on that system.

modified

Returns the time that the path was last modified (mtime).

changed

Returns the time that the path was last changed (modified or a metadata change).

stat

Returns a stat buffer for the path.

TODO: methods created, accessed, modified: return format, failure

IO::Path

    class IO::Path is Cool does IO::FileTestable { }

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

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

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

    path              volume         directory  base name
    /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

IO::Path uses the syntax for the current operating system. If you want to work paths as if you were using another OS, use the OS-specific subclasses such as IO::Path::Cygwin.

There are several ways of creating an IO::Path. Both IO::Handle and Cool have a .path method, or you can construct it directly:

        "my/path".path
        $filehandle.path
        IO::Path.new( $full-path );
        IO::Path.new( :$volume, :$directory, :$basename);
Str

Stringification returns the path (volume, directory and base name joined together) as a string.

volume

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.

directory

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

basename

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

path

Returns the entire IO::Path object (a no-op).

contents
    method contents( Mu :$test = none('.', '..') )

Returns a lazy list of file names in the path, if it is a directory. The current and the parent directory are excluded, which can be controlled with the $test named parameter. Only items that smart-match against this test are returned.

The return value is a list of IO::Path objects. Because of this, you may want use the basename method on the results to get the just the file name, without its full path.

cleanup
        method cleanup( :$parent = False )

Returns a new IO::Path object with the canonical path. This eliminates extra slashes and '.' directories, but leaves '..' in (or whatever the parent directory is called on that platform).

With :parent, cleanup will logically remove references to the parent directory without checking the filesystem. That is, the parent of a symbolic link will remove the symlink itself, not the parent of the symlink's destination.

resolve

Returns a new IO::Path object that is cleaned-up (as above), and all symbolic links and references to the parent directory (..) are physically resolved. This means that the filesystem is examined for each directory in the path, and any symlinks found are followed. Identical to .cleanup(:parent) on systems where symbolic links are not supported.

   # bar is a symlink pointing to "/baz"
   my $path = "foo/./bar///..".path;
   $path.=cleanup;  # now "foo/bar/.."
   $path.cleanup(:parent); # yields "foo"
   $path.=resolve;  # now "/" (the parent of "/baz")
is-relative

Returns True if the path is a relative path (like foo/bar), False otherwise.

is-absolute

Returns True if the path is an absolute path (like /usr/bin), False otherwise.

absolute
    method absolute ( Str $base = $*CWD )

Transforms the path into an absolute form, and returns the result as a new IO::Path. If $base is supplied, transforms it relative to that base directory; otherwise the current working directory is used. Paths that are already absolute are returned unchanged.

relative
    method relative ( Str $base = $*CWD )

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

parent

Removes the last portion the given path, and returns a new IO::Path. This does not remove ., .., or symbolic links, so you may want to consider calling cleanup or resolve first.

On a Unix/POSIX filesystem, if called recursively, it will work like so:

    parent level          relative       absolute
    Starting Path (0)     foo/bar        /foo/bar
    1                       foo            /foo
    2                        .              /
    3                        ..             /
    4                      ../..            /
    5                     ../../..          /
child
    method child ( Str $childname )

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

succ

Increments the basename portion of the string, as Str.succ does, and returns that successor as an IO::Path.

This is useful for getting all the parts of say, a multi-part archive, but does not always return the next item in the folder. To crawl a folder, you probably want to iterate on the parent directory's contents.

pred

Decrements the basename portion of the string, as Str.pred does, and returns that predecessor as an IO::Path.

copy
    method copy ($dest, :$createonly = False )

Copies a file from the path, to the destination specified. If :createonly is set to True, copy fails when a file already exists in the destination. If the operation cannot be completed, fails as X::IO::Copy.

unlink

Unlinks (deletes) the ordinary file, link, or symbolic link represented by the IO::Path. Returns True on success; on error, fails with an X::IO::Unlink.

rmdir

Removes (deletes) the directory represented by the IO::Path. Typically fails unless the directory is empty. Returns True on success; fails with an X::IO::Rmdir on error.

mkdir

Makes (creates) the directory represented by the IO::Path. Returns True on success. The method will fail with X::IO::Mkdir if it can not create the directory, if file or directory already exists or if the parent directory of the path does not exist.

OS Specific subclasses.

IO::Path::Unix, IO::Path::Win32, and IO::Path::Cygwin subclasses are available for manipulating paths from different operating systems than the one you're currently using. Unix works with any POSIX-like operating system, such as Linux or Darwin. Win32 works for paths from Windows, DOS, OS/2, NetWare, and Symbian.

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 are less convenient than in IO::Path, but it allows access to lower-level operations on file path strings.

As with IO::Path, these operations are significantly different on some operating systems, so we have the following subclasses: IO::Spec::Unix, IO::Spec::Win32, and IO::Spec::Cygwin. IO::Spec automatically loads the correct module for use on the current system.

Each class can (and should) be used in its undefined form:

    my $cleanpath = IO::Spec.canonpath("a/.//b/")  # gives "a/b"

Although we inherit a lot from Perl 5's File::Spec, some things have changed: no_updirs has been removed (but see no-parent-or-current-test) and case_tolerant has also been removed (and put in a module). Method join is no longer an alias for catfile, but is now a function similar to catpath.

Each of the following methods are available under the subclasses, with the exception of os.

os

The os method takes a single argument, an operating system string, and returns an IO::Spec object for the appropriate OS.

    my $mac_os_x_spec = File::Spec.os('darwin');
    # returns a File::Spec::Unix object
    my $windows_spec = File::Spec.os('MSWin32');
    #returns File::Spec::Win32
    say File::Spec.os('Win32').canonpath('C:\\foo\\.\\bar\\');
    # prints "C:\foo\bar"

The parameter can be either an operating system string, or the last part of the name of a subclass ('Win32', 'Mac'). The default is `$*OS`, which gives you the same subclass that IO::Spec already uses for your system.

This is only implemented by the IO::Spec class, and not its subclasses.

canonpath

No physical check on the filesystem, but a logical cleanup of a path.

    $cpath = IO::Spec.canonpath( $path ) ;

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

is-absolute

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

    $is_absolute = IO::Spec.is-absolute( $path );
splitpath
    method splitpath( $path, $nofile = False )

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

    my ($volume,$directories,$file) = IO::Spec.splitpath( $path );
    my ($volume,$directories,$file) = IO::Spec.splitpath( $path, $no_file );

For systems with no syntax differentiating filenames from directories, assumes that the last file is a path unless $no_file is true or a trailing separator or /. or /.. is present. On Unix, this means that $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 "catpath()" to get back a path equivalent to (usually identical to) the original path.

split

A close relative of `splitdir`, this function also splits a path into volume, directory, and filename portions. Unlike splitdir, split returns paths compatible with dirname and basename and returns it arguments as a hash of volume, directory, and 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, '.', or '..'. If a relative path's directory portion would otherwise be empty, the directory is set to '.' (or whatever curdir is).

On systems with no concept of volume, returns '' (the empty string) for volume.

    my %splitfile = IO::Spec.split( $path );
    say IO::Spec::Win32( "C:\\saga\\waffo\\" );
        # ("volume" => "C:", "directory" => "\\saga", "basename" => "waffo")

The results can be passed to `.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 `.splitdir` instead.

Comparison of splitpath and split
    OS      Path       splitpath               split (.values)
    linux   /a/b/c     ("", "/a/b/", "c")      ("", "/a/b", "c")
    linux   /a/b//c/   ("", "/a/b//c/", "")    ("", "/a/b", "c")
    linux   /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.

catpath()

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

    $full_path = IO::Spec.catpath( $volume, $directory, $file );
join

A close relative of `.catpath`, this function takes volume, directory and basename portions and returns an entire path string. If the dirname is `'.'`, it is removed from the (relative) path output, because this function inverts the functionality of dirname and basename.

    $full-path = IO::Spec.join(:$volume, :$directory, :$basename);
    say IO::Spec::Unix.join( directory => '/hobbit', basename => 'frodo' );
        # "/hobbit/frodo"

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 `.split`; the results can be passed to it to get the volume, dirname, and basename portions back.

Comparison of catpath and join
    OS     Components            catpath        join
    linux  ("", "/a/b", "c")     /a/b/c         /a/b/c
    linux  ("", ".", "foo")      ./foo          foo
    linux  ("", "/", "/")        //             /
    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.

splitdir

The opposite of "catdir".

    @dirs = IO::Spec.splitdir( $directories );

$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 ('') can be returned, because these are significant on some OSes.

catdir

Concatenate two or more directory names to form a complete path ending with a directory. Removes any trailing slashes from the resulting string, unless it's the root directory.

    $path = IO::Spec.catdir( @directories );
catfile

Concatenate one or more directory names and a filename to form a complete path ending with a filename

    $path = IO::Spec.catfile( @directories, $filename );
abs2rel

Takes a destination path and an optional base path returns a relative path from the base path to the destination path:

    $rel_path = IO::Spec.abs2rel( $path ) ;
    $rel_path = IO::Spec.abs2rel( $path, $base ) ;

If $base is not present or '', then $*CWD is used. If $base is relative, then it is converted to absolute form using "IO::Spec/rel2abs". This means that it is taken to be relative to $*CWD.

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

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

If $path is relative, it is converted to absolute form using "IO::Spec/rel2abs". This means that it is taken to be relative to $*CWD.

No checks against the filesystem are made.

rel2abs

Converts a relative path to an absolute path.

    $abs_path = IO::Spec.rel2abs( $path ) ;
    $abs_path = IO::Spec.rel2abs( $path, $base ) ;

If $base is not present or '', then $*CWD is used. If $base is also relative, then it is first converted to absolute form, relative to $*CWD.

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

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

If $path is absolute, it is cleaned up and returned using "canonpath".

No checks against the filesystem are made.

curdir

Returns a string representation of the current directory (. on Linux and Windows).

    my $curdir = IO::Spec.curdir;
updir

Returns a string representation of the parent directory (.. on Linux and Windows).

    my $updir = IO::Spec.updir;
rootdir

Returns a string representation of the root directory (/ on Linux).

    my $rootdir = IO::Spec.rootdir;
devnull

Returns a string representation of the null device (/dev/null on Linux).

    my $devnull = IO::Spec.devnull;
path

Takes no argument. Returns the environment variable PATH (or the local platform's equivalent) as a list.

    my @PATH = IO::Spec.path;
tmpdir

Returns a string representation of the first writable directory from a 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; e.g. IO::Spec::Unix checks %*ENV<TMPDIR> and /tmp.

    $tmpdir = IO::Spec.tmpdir;
no-parent-or-current-test

Returns a test as to whether a given path is identical to the parent or the current directory. On Linux, this is simply none('.', '..'). The "Functions/dir" function automatically removes these for you in directory listings, so under normal circumstances you shouldn't need to use it directly.

    'file' ~~ IO::Spec.no-parent-or-current-test    #False
    '.'    ~~ IO::Spec.no-parent-or-current-test    #True
    '..'   ~~ IO::Spec.no-parent-or-current-test    #True

This can, however, be used to extend dir() through its `$test` parameter:

    dir( "my/directory", test=>
      all(IO::Spec.no-parent-or-current-test, /^ '.' /));

This example would return all files beginning with a period that are not `.` or `..` directories. This would work similarly with IO::Path.contents.

This method replaces the functionality of the Perl 5 no_updirs method.

Here Be Dragons

Everything below this point hasn't been reviewed properly

IO::Socket

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

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

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

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
open
    method open()

If $.Listener is true, does a bind(2) and a listen(2), otherwise does a 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.

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').

shutdown
    method shutdown(Str @how)

Does a 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'.

accept
    method accept( --> IO::Socket)
method read(Int $bytes --> Buf)

Reads and returns $bytes bytes from the handle

method write(Buf $buf --> Int)

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

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;
        ...
    }
new
    multi method new(:$host!, :$port, *%attributes) { ... }
    multi method new(:$localhost!, :$localport, :$listen! *%attributes) { ... }

Creates a new socket and opens it.

IO::Handle (opened version)

This role indicates that this object actually represents an open file descriptor in the os level.

method int fileno()

File descriptors are always native integers, conforming to C89.

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.

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 %permissions are:

Readable

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

Writeable

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

Executable

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

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.

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

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.

close()

If the file handle came from a piped open, close will additionally return Failure (aliased to $!) 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 Failure object if necessary.

IO::Pipe.to
    method to(Str $command, *%opts --> Bool)
    method to(Str *@command, *%opts --> Bool)

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

IO::Pipe.from
    method from(Str $command, *%opts --> Bool)
    method from(Str *@command, *%opts --> Bool)

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

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

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

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

OS-specific classes

Unix

Path::Unix

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 fchown, you might pass file handles among the files. On systems that don't support 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);
chmod LIST

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 not be a string of octal digits: 0o644 is okay, 0644 is not. Returns the number of files successfully changed.

    $count = chmod 0o755, 'foo', 'bar';
    chmod 0o755, @executables;
    $mode = '0644'; chmod $mode, 'foo';      # !!! sets mode to --w----r-T
    $mode = '0o644'; chmod $mode, 'foo';     # this is better
    $mode = 0o644;   chmod $mode, 'foo';     # this is best
stat
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.

IO::Socket::Unix

    role IO::Socket::Unix does IO::Socket {
        has Str $.RemoteAddr, # Remote Address
        has Str $.LocalAddr,  # Local Address
    }
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
    ) {...}
pair
    method pair(Int $domain, Int $type, Int $protocol --> List of IO)

A wrapper for socketpair(2), returns a pair of 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);

IO::POSIX

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

method dup( --> IO)
has Bool $.blocking is rw
method flock(:$r,:$w --> Bool)
method funlock( --> Bool)
...

Unfilled

IO.ioctl

Available only as a handle method.

alarm
prompt
    multi prompt (Str $prompt --> Str)

Should there be an IO::Interactive role?

Str.readpipe
sysopen
IO.sysseek
umask

Removed functions

IO.eof

Gone, see eoi IO::Seekable.

IO.fileno

See IO::Handle.

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

Should be implemented by an external library.

lstat

Use stat with the :link option.

IO.name

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

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

pipe

Gone, see Pipe.pair

select(both)

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

IO.shutdown()

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

socketpair

Gone, see Socket.pair

IO.sysread

Gone, see IO::Readable.read().

IO.syswrite

Gone, see IO::Writeable.read().

utime

Gone, see Path.times.

IO::Buffered

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

method flush( --> Bool)

Flushes the buffers associated with this object.

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; $OUT_FH.autoflush tells you only whether you've asked Perl explicitly to flush after each write). $*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.

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 {...}
new()
    method new(
        Bool :$NoOpen,
        Bool :$Blocking,
        --> IO::Streamable
    ) {...}

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

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

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.

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 IO::Streamable of the appropriate type, and throws an error when an inappropriate type is passed in. For example, calling IO::File.uri('http://....') will throw an error (but will suggest using just uri('http://...') instead).

IO::Encoded

This is a generic role for encoded data streams.

method encoding( --> Str) is rw
method locale( --> Str) is rw

Encoding and locale are required for sane conversions.

IO::Readable::Encoded

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

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

Returns an appropriate 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.

%*PROTOCOLS dynamic variable

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

AUTHORS

    The authors of the related Perl 5 docs
    Rod Adams <rod@rodadams.net>
    Larry Wall <larry@wall.org>
    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>

POD ERRORS

Hey! The above document had some coding errors, which are explained below:

Around line 5:

Non-ASCII character seen before =encoding in '=encoding'. Assuming UTF-8

[ Top ]   [ Index of Synopses ]