=begin pod

=TITLE class IO::Handle

=SUBTITLE Opened file or stream

   class IO::Handle { }

=head1 Methods

=head2 method get

Reads a single line from the input stream (usually the Standard Input or a file).

Read one line from the standard input:

=for code :skip-test
$*IN.get;

Read one line from a file:

=for code :skip-test
my $fh = open 'filename';
my $line = $fh.get;


=head2 method getc

Read a single character from the input stream or return Nil. The operation will block
for at least one character to be available, but there are a few caveats for this:

=head3 Buffering terminals

Using getc to get a single keypress from a terminal will only work properly if
you've set the terminal to "unbuffered". Otherwise the terminal will wait for
the return key to be struck or the buffer to be filled up before perl6 gets
even a single byte of data.

=head3 Waiting for potential combiners

If your handler's encoding allows combining characters to be read, perl6 will
wait for more data to be available before it provides a character. This means
that inputting an "e" followed by a combining acute will give you an e with an
acute rather than giving an "e" and letting the next reading function give you
a dangling combiner. However, it also means that when the user inputs just an
"e" and has no intention to also input a combining acute, your program will be
waiting for another keypress before the initial "e" is returned.

=head2 method eof

Returns C<True> if the read operations have exhausted the content of the file.

=head2 method lines

    method lines($limit = Inf)

Return a lazy list of the file's lines read via L<get>, limited to C<$limit> lines.
The new line separator (i.e., C<$*IN.nl-in>) will be excluded.

=for code :skip-test
my @data;
my $data-file = open 'readings.csv';
for $data-file.lines -> $line {
    @data.push($line.split(','))
}

=head2 method lock

    method lock(IO::Handle:D:
        Bool:D :$non-blocking = False, Bool:D :$shared = False --> True
    )

Places an advisory lock on the filehandle. If C<:$non-blocking> is C<True>
will L«C<fail>|/routine/fail» with C<X::IO::Lock> if lock could not be
obtained, otherwise will block until the lock can be placed. If C<:$shared>
is C<True> will place a shared (read) lock, otherwise will place an
exclusive (read) lock. On success, returns C<True>; L«fails|/routine/fail»
with C<X::IO::Lock> if lock cannot be placed (e.g. when trying to place
a shared lock on a filehandle opened in write mode or trying to
place an exclusive lock on a filehandle opened in read mode).

You can use C<lock> again to replace an existing lock with another one.
Use L«C<close>|/routine/close» the filehandle or use
L«C<unlock>|/routine/unlock» to remove a lock.

=for code :skip-test
# One program writes, the other reads, and thanks to locks either
# will wait for the other to finish before proceeding to read/write

# Writer
with "foo".IO.open(:w) {
    .lock;
    .spurt: "I ♥ Perl 6!";
    .close;
}

# Reader
with "foo".IO.open {
    .lock: :shared;
    .slurp.say; # OUTPUT: «I ♥ Perl 6!␤»
    .close;
}

=head2 method unlock

    method unlock(IO::Handle:D: --> True)

Removes a L«C<lock>|/routine/lock» from the filehandle.

=head2 method words

    method words($count = Inf)

Return a lazy list of the file's words (separated on whitespace), limited
to C<$count> words.

=for code :skip-test
my %dict;
++%dict{$_} for $*IN.words;
say "Most common words: ", %dict.sort(*.value).reverse.[^5];

=head2 method split

    multi method split(IO::Handle:D: :$close = False, :$COMB)
    multi method split(IO::Handle:D: $splitter, :$close = False, :$COMB)

Returns a lazy list of strings found between the splitter, just like C<split>
on strings.

=for code :skip-test
my $fh = open 'path/to/file', :r;
$fn.split(' ', close => True); # Returns file content split by a space and closes file;

=head2 method spurt

    multi method spurt(IO::Handle:D: Blob $data, :$close = False)
    multi method spurt(IO::Handle:D: Cool $data, :$close = False)

Writes all of the C<$data> into the filehandle, closing it when finished,
if C<$close> is C<True>. For L«C<Cool>|/type/Cool» C<$data>, will use the
encoding the handle is set to use (L«C<IO::Handle.open>|/routine/open»
or L«C<IO::Handle.encoding>|/routine/encoding»).

Behaviour for spurting a L«C<Cool>|/type/Cool» when the handle is in binary
mode or spurting a L«C<Blob>|/type/Blob» when the handle is NOT in binary
mode is undefined.

=head2 method comb

    multi method comb(IO::Handle:D: :$close = False)
    multi method comb(IO::Handle:D: Int:D $size, :$close = False)
    multi method comb(IO::Handle:D: $comber, :$close = False)

Returns a lazy list of strings combed from the handle, just like C<comb>
on strings.

=for code :skip-test
my $fh = open 'path/to/file', :r;
$fn.comb(/A+/); # Comb file contents by a regex.

or

=for code :skip-test
my $fh = open 'path/to/file', :r;
$fn.comb(3, close => True); # Comb file contents by 3 characters and close after.

=head2 method print

    method print(*@text --> Bool)

Text writing; writes the given C<@text> to the filehandle.  See L<write>
to write bytes.

=for code :skip-test
my $fh = open 'path/to/file', :w;
$fh.print("some text\n");
$fh.close;

=head2 method print-nl

    method print-nl(IO::Handle:D: --> True)

Writes a newline to the filehandle. The newline marker, which is stored
in the attribute C<$.nl-out>, defaults to C<\n> unless another marker has
been specified in the call to L<open>.

=for code :skip-test
my $fh = open 'path/to/file', :w, nl-out => "\r\n";
$fh.print("some text");
$fh.print-nl;                                        # \r\n
$fh.close;

=head2 method printf

    method printf(IO::Handle:D: Cool $format, *@args)

Formats a string based on the given format and arguments and C<.print>s the
result into the filehandle.
See L<sub sprintf|https://docs.perl6.org/type/Str#sub_sprintf> for details
on acceptable format directives.

=for code :skip-test
my $fh = open 'path/to/file', :w;
$fh.printf: "The value is %d\n", 32;
$fh.close;

=head2 method say

    method say(IO::Handle:D: |)

This method is identical to L<print|/type/IO::Handle#method_print> except
that it stringifies its arguments by calling C<.gist> on them and
auto-appends a newline, with a call to L<print-nl|/type/IO::Handle#method_print-nl>,
after the final argument.

=for code :skip-test
my $fh = open 'path/to/file', :w;
$fh.say(Complex.new(3, 4));        # RESULT: «3+4i\n»
$fh.close;

=head2 method read

    method read(IO::Handle:D: Int(Cool:D) $bytes --> Blob)

Binary reading; reads and returns up to C<$bytes> bytes from the filehandle.

=head2 method readchars

    method readchars(IO::Handle:D: Int(Cool:D) $chars --> Str)

Reading chars; reads and returns up to C<$chars> chars (graphemes) from the
filehandle.

=head2 method write

    method write(IO::Handle:D: Blob:D $buf)

Binary writing; writes C<$buf> to the filehandle.  See L<print> to write
characters.

=head2 method seek

     method seek(IO::Handle:D: Int:D $offset, SeekType:D $whence --> True)

Move the file pointer (that is, the position at which any subsequent read
or write operations will begin) to the byte position specified by
C<$offset> relative to the location specified by C<$whence> which may be
one of:

=item SeekFromBeginning

The beginning of the file.

=item SeekFromCurrent

The current position in the file.

=item SeekFromEnd

The end of the file.  Please note that you need to specify a negative
offset if you want to position before the end of the file.

=head2 method tell

    method tell(IO::Handle:D: --> Int)

Return the current position of the file pointer in bytes.

=head2 method slurp-rest

    multi method slurp-rest(IO::Handle:D: :$bin! --> Buf)
    multi method slurp-rest(IO::Handle:D: :$enc --> Str)

B<DEPRECATION NOTICE:> this method will be deprecated in C<6.d> language. Do
not use it for new code. Use L«C<.slurp> method|/routine/slurp» method
instead.

Return the remaining content of the file from the current file position
(which may have been set by previous reads or by C<seek>.)  If the
adverb C<:bin> is provided a L<Buf> will be returned,
otherwise the return will be a C<Str> with the optional encoding C<:enc>.

=head2 method slurp

    method slurp(IO::Handle:D: :$close = False)

Returns all the content from the current file position to the end.
If the invocant is in binary mode, will return L<Buf>, otherwise will decode
the content using invocant's current L«C<.encoding>|/routine/encoding» and
return a L<Str>.

If C<:$close> is set to C<True>, will close the handle when finished reading.

=head2 method Supply

    multi method Supply(IO::Handle:D: :$size = 65536)

Returns a C<Supply> that will emit the contents of the handle in chunks.
The chunks will be L«C<Buf>|/type/Buf» if the handle is in binary mode
or, if it isn't, L«C<Str>|/type/Str» decoded using same encoding as L«C<IO::Handle.encoding>|/routine/encoding».

The size of the chunks is determined by the optional C<:size> named
parameter and C<65536> bytes in binary mode or C<65536> characters in non-binary
mode.

=for code :skip-test
    "foo".IO.open(:bin).Supply(:size<10>).tap: *.perl.say;
    # OUTPUT:
    # Buf[uint8].new(73,32,226,153,165,32,80,101,114,108)
    # Buf[uint8].new(32,54,33,10)

    "foo".IO.open.Supply(:size<10>).tap: *.perl.say;
    # OUTPUT:
    # "I ♥ Perl 6"
    # "!\n"


=head2 method path

For a handle opened on a file this returns the L<IO::Path|/type/IO::Path> that
represents the file. For the standard I/O handles C<$*IN>, C<$*OUT>,
and C<$*ERR> it returns an L<IO::Special|/type/IO::Special> object.

=head2 method IO

Alias for L«C<.path>|/type/IO::Handle#method_path»

=head2 method Str

Returns the value of L«C<.path>|/type/IO::Handle#method_path», coerced
to L<Str>.

=for code :skip-test
    say "foo".IO.open.path; # OUTPUT: «"foo".IO␤»

=head2 method close

Will close a previously opened filehandle.

=for code :skip-test
$fh.close;

=head2 method flush

Will flush the filehandle to disk.

=for code :skip-test
$fh.flush;

=head2 method native-descriptor

    method native-descriptor()

This returns a value that the operating system would understand as a "file descriptor" and
is suitable for passing to a native function that requires a file descriptor as an
argument such as C<fcntl> or C<ioctl>.

=head2 method opened

    method opened(IO::Handle:D: --> Bool)

Returns C<True> if the handle is open.

=head2 method t

    method t(IO::Handle:D: --> Bool)

Returns C<True> if the handle is opened to a tty.

=head1 Related roles and classes

See also the related role L<IO> and the related class L<IO::Path>.

=end pod

# vim: expandtab shiftwidth=4 ft=perl6
