Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl 6 $*ARGFILES.handles in binary mode?

Tags:

raku

I'm trying out $*ARGFILES.handles and it seems that it opens the files in binary mode.

I'm writing a zip-merge program, that prints one line from each file until there are no more lines to read.

#! /usr/bin/env perl6

my @handles = $*ARGFILES.handles;

# say $_.encoding for @handles;

while @handles
{
  my $handle = @handles.shift;
  say $handle.get;
  @handles.push($handle) unless $handle.eof;
}

I invoke it like this: zip-merge person-say3 repeat repeat2

It fails with: Cannot do 'get' on a handle in binary mode in block at ./zip-merge line 7

The specified files are text files (encoded in utf8), and I get the error message for non-executable files as well as executable ones (with perl6 code).

The commented out line says utf8 for every file I give it, so they should not be binary,

perl6 -v: This is Rakudo version 2018.10 built on MoarVM version 2018.10

Have I done something wrong, or have I uncovered an error?

like image 996
Arne Sommer Avatar asked Dec 05 '18 19:12

Arne Sommer


2 Answers

The IO::Handle objects that .handles returns are closed.

my @*ARGS = 'test.p6';
my @handles = $*ARGFILES.handles;
for @handles { say $_ }
# IO::Handle<"test.p6".IO>(closed)

If you just want get your code to work, add the following line after assigning to @handles.

.open for @handles;

The reason for this is the iterator for .handles is written in terms of IO::CatHandle.next-handle which opens the current handle, and closes the previous handle.
The problem is that all of them get a chance to be both the current handle, and the previous handle before you get a chance to do any work on them.
(Perhaps .next-handle and/or .handles needs a :!close parameter.)


Assuming you want it to work like roundrobin I would actually write it more like this:

# /usr/bin/env perl6
use v6.d;

my @handles = $*ARGFILES.handles;

# a sequence of line sequences
my $line-seqs = @handles.map(*.open.lines);
# Seq.new(
#   Seq.new( '# /usr/bin/env perl6', 'use v6.d' ), # first file
#   Seq.new( 'foo', 'bar', 'baz' ),                # second file
# )

for flat roundrobin $line-seqs {
  .say
}

# `roundrobin` without `flat` would give the following result

# ('# /usr/bin/env perl6', 'foo'),
# ('use v6.d', 'bar'),
# ('baz')

If you used an array for $line-seqs, you will need to de-itemize (.<>) the values before passing them to roundrobin.

for flat roundrobin @line-seqs.map(*.<>) {
  .say
}

Actually I personally would be more likely to write something similar to this (long) one-liner.

$*ARGFILES.handles.eager».open».lines.&roundrobin.flat.map: *.put
like image 91
Brad Gilbert Avatar answered Sep 28 '22 01:09

Brad Gilbert


:bin is always set in this type of objects. Since you are working on the handles, you should either read line by line as instructed on the example, or reset the handle so that it's not in binary mode.

like image 26
jjmerelo Avatar answered Sep 28 '22 01:09

jjmerelo