How should I handle Perl 6 $*ARGFILES that can'

2019-06-15 14:58发布

I'm playing around with lines which reads lines from the files you specify on the command line:

for lines() { put $_ }

If it can't read one of the filenames it throws X::AdHoc (one day maybe it will have better exception types so we can grab the filename with a .path method). Fine, so catch that:

try {
CATCH { default { put .^name } }
for lines() { put $_ }
}

So this catches the X::AdHoc error but that's it. The try block is done at that point. It can't .resume and try the next file:

try {
CATCH { default { put .^name; .resume } }  # Nope
for lines() { put $_ }
}

Back in Perl 5 land you get a warning about the bad filename and the program moves on to the next thing.

I could filter @*ARGS first then reconstruct $*ARGFILES if there are some arguments:

$*ARGFILES = IO::CatHandle.new:  
    @*ARGS.grep( { $^a.IO.e and $^a.IO.r } ) if +@*ARGS;

for lines() { put $_ }

That works although it silently ignores bad files. I could handle that but it's a bit tedious to handle the argument list myself, including - for standard input as a filename and the default with no arguments:

my $code := { put $_ };

@*ARGS = '-' unless +@*ARGS;
for @*ARGS -> $arg {
    given $arg {
        when '-'     { $code.($_) for $*IN.lines(); next }
        when ! .IO.e { note "$_ does not exist";    next }
        when ! .IO.r { note "$_ is not readable";   next }
        default      { $code.($_) for $arg.IO.lines() }
        }
    }

But that's a lot of work. Is there a simpler way to handle this?

标签: io perl6 raku
1条回答
Lonely孤独者°
2楼-- · 2019-06-15 15:24

To warn on bad open and move on, you could use something like this:

$*ARGFILES does role { method next-handle { loop {
    try return self.IO::CatHandle::next-handle;
    warn "WARNING: $!.message"
}}}

.say for lines

Simply mixing in a role that makes the IO::CatHandle.next-handle method re-try getting next handle. (you can also use but operator to mixin on a copy instead).


If it can't read one of the filenames it throws X::AdHoc

The X::AdHoc is from .open call; there's a somewhat moldy PR to make those exceptions typed, so once that's fixed, IO::CatHandle would throw typed exceptions as well.

It can't .resume

Yeah, you can only resume from a CATCH block that caught it, but in this case it's caught inside .open call and is made into a Failure, which is then received by IO::CatHandle.next-handle and its .exception is re-.thrown.

However, even if it were resumable here, it'd simply resume into a path where exception was thrown, not re-try with another handle. It wouldn't help. (I looked into making it resumable, but that adds vagueness to on-switch and I'm not comfortable speccing that resuming Exceptions from certain places must be able to meaningfully continue—we currently don't offer such a guarantee for any place in core).

including - for standard input as a filename

Note that that special meaning is going away in 6.d language as far as IO::Handle.open (and by extension IO::CatHandle.new) goes. It might get special treatment in IO::ArgFiles, but I've not seen that proposed.


Back in Perl 5 land you get a warning about the bad filename and the program moves on to the next thing.

In Perl 6, it's implemented as a generalized IO::CatHandle type users can use for anything, not just file arguments, so warning and moving on by default feels too lax to me.

IO::ArgFiles could be special-cased to offer such behaviour. Personally, I'm against special casing stuff all over the place and I think that is the biggest flaw in Perl 5, but you could open an Issue proposing that and see if anyone backs it.

查看更多
登录 后发表回答