On Mon, 19 Feb 2018 16:15:37 -0800, comdog wrote:
> #!/Users/brian/bin/perl6s/perl6-latest
>
> I'm playing with .next-handle from IO::CatHandle. I'm
> trying to create a situation where I can read just the first five
> lines from each command line argument:
>
> quietly {
> my $limit = 5;
> for lines() {
> state $lines = 1;
> FIRST { $*ARGFILES.on-switch = { put "NEW FILE"; $lines = 1 } }
> if $lines > $limit {
> $*ARGFILES.next-handle;
> next;
> }
> put "{$*ARGFILES.path}:{$lines++} $_";
> }
> }
>
> Here's a test file:
>
> First
> Second
> Third
> Fourth
> Fifth
> Six
> Seventh
>
> With one or more command-line arguments I get this odd behavior (and
> lots of warnings that I suppressed):
>
> test.txt:1 First
> test.txt:2 Second
> test.txt:3 Third
> test.txt:4 Fourth
> test.txt:5 Fifth
> NEW FILE
> :1 Seventh
> read bytes requires an object with REPR MVMOSHandle (got VMNull
> with REPR Null)
> in block <unit> at lines-method.p6 line 5
>
> It does "switch" after five lines, but then it keeps reading from the
> same handle while losing a line. Then there's a strange error at the
> end that kills the whole thing.
>
> I expected that it would close the current handle, open a new one, and
> continue. If it gets to the end, it would simply not provide any more
> lines() and things would end normally.
>
> The docs for .next-handle lets you keep changing it as long as you
> like no matter how many
>
> -----
>
> This is Rakudo Star version 2018.01 built on MoarVM version 2018.01
> implementing Perl 6.c.
This is because current implementation of IO::CatHandle.lines simply flattens
a gather/taken .lines Seq from each handle, so it never expects the handles to
get switched before each .lines Seq is fully-consumed. The .next-handle closes
the previous handle, which is where the weird error comes from (it tries to use
the now-nulled $!PIO to .read/.eof from). Pretty sure .words is similarly
affected.
I think if we give IO::CatHandle!LINES and IO::CatHandle!WORDS their own
iterators that basically do the same thing as IO::Handle ones and then make
.next-handle also toss the remaining data in the $!decoder, then the OP code
would work.
In the meantime, you can use `.get` instead:
my $limit := 3;
my $lines = 1;
with $*ARGFILES -> $af {
while ($_ := $af.get) !=:= Nil {
$lines == 1 and put "NEWFILE:";
put "$af.path():{$lines++} $_";
next unless $lines > $limit;
$af.next-handle and $lines = 1;
}
}
I also noticed another deficiency: when trying to set .on-switch on $*ARGFILES,
you always miss its very first call that's done by IO::CatHandle.new, since to
give
you $*ARGFILES, .new has already been called.
Not sure what can be done about it, but I filed it as
https://github.com/rakudo/rakudo/issues/1545 IO::CatHandle is not yet part of
any
language, so we have the ability to polish the rough edges.