Как я должен обрабатывать Perl 6 $* ARGFILES, которые не могут быть прочитаны строками()?

Я играю с lines, который читает строки из файлов, которые вы указали в командной строке:

for lines() { put $_ }

Если он не может прочитать один из имен файлов, он бросает X::AdHoc (в один прекрасный день, возможно, у него будут лучшие типы исключений, чтобы мы могли захватить имя файла с помощью метода .path). Отлично, так поймите, что:

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

Таким образом, это улавливает ошибку X::AdHoc, но это. Блок try выполняется в этой точке. Он не может .resume и попробуйте следующий файл:

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

Вернитесь на сервер Perl 5, вы получите предупреждение о неправильном имени файла, и программа перейдет к следующему.

Я мог бы фильтровать @*ARGS сначала, а затем восстановить $*ARGFILES, если есть некоторые аргументы:

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

for lines() { put $_ }

Это работает, хотя он молча игнорирует плохие файлы. Я мог бы справиться с этим, но немного утомительно обрабатывать список аргументов, включая - для стандартного ввода в качестве имени файла и по умолчанию без аргументов:

my $code := { put $_ };

@*ARGS = '-' unless [email protected]*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() }
        }
    }

Но это много работы. Есть ли более простой способ справиться с этим?

Ответ 1

Чтобы предупредить о плохой открытости и двигаться дальше, вы можете использовать что-то вроде этого:

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

.say for lines

Просто смешивание в роли, которое делает IO:: CatHandle. next-handle повторите попытку получения следующего дескриптора. (вы можете также использовать but operator для микширования вместо копии).


Если он не может прочитать одно из имен файлов, он выбрасывает X:: AdHoc

X::AdHoc - вызов .open; там несколько заплесневелый PR, чтобы эти исключения были напечатаны, поэтому после того, как исправлено, IO::CatHandle также выдаст типизированные исключения.

Он не может .resect

Да, вы можете возобновить только с блока CATCH, который его поймал, но в этом случае он попал внутрь вызова .open и был сделан в Failure, который затем принимается IO::CatHandle.next-handle и его .exception is re .throw n.

Однако, даже если бы он был возобновлен здесь, он просто возобновил бы путь, где было выбрано исключение, а не повторять попытку с другим дескриптором. Это не помогло бы. (Я задумался о том, чтобы сделать его возобновляемым, но это добавляет неопределенность в on-switch, и мне не удобно указывать, что возобновление Exception из определенных мест должно быть в состоянии значимо продолжиться - мы в настоящее время не предлагаем такую ​​гарантию для любого места в ядре).

включая - для стандартного ввода в качестве имени файла

Обратите внимание, что это специальное значение уходит на 6.d-языке до IO::Handle.open (и по расширению IO::CatHandle.new) идет, Он может получить специальное лечение в IO::ArgFiles, но я не видел этого.


Вернитесь на сервер Perl 5, вы получите предупреждение о неправильном имени файла, и программа перейдет к следующему.

В Perl 6 он реализован как обобщенный тип IO::CatHandle, который пользователи могут использовать для чего угодно, а не только для аргументов файла, поэтому предупреждение и перемещение по умолчанию кажется мне слишком слабым.

IO::ArgFiles может быть специальным, чтобы предлагать такое поведение. Лично я против специальных предметов корпуса повсюду, и я думаю, что это самый большой недостаток в Perl 5, но вы могли открыть проблему, предлагая, чтобы и посмотрите, поддерживает ли его.