Передача подпрограммы в подпрограмму Perl

Я пытаюсь сделать подпрограмму, имитирующую Perl6/Raku dir. dir может очень легко и быстро искать каталоги с файловыми тестами в каталоге.

Я пытаюсь добавить рекурсивную опцию в dir.

У меня есть скрипт, который может это сделать, но я пытаюсь добавить рекурсивную опцию, используя скрипт File::Find, который, как я уже знаю, работает:

use File::Find;
my @files;
find({ wanted => \&process_file, no_chdir => 1 }, '.');
sub process_file {
    if ((-f $_) && ($_ =~ m/\.pl$/)) {#various tests on the files
            push @files, $_;
#        print "This is a file: $_\n";
    }
}

Однако я хочу сделать все в одной подпрограмме.

Я пробовал это:

use strict;
use warnings FATAL => 'all';
use feature 'say';
use autodie ':all';
use Carp 'confess';
use File::Find 'find';

sub dir { # a Perl5 mimic of Perl6/Raku's "dir"
    my %args = ( # default arguments listed below
        tests => 'f', dir => '.', regex   => '.', recursive => 0,
    @_, # argument pair list goes here
    );
    if ($args{tests} =~ m/[^rwxoRWXOezfdlpSbctugkTB]/){# sMAC returns are non-boolean, and are excluded
        confess "There are some unrecognized characters in $args{tests}";
    }
    my @items = split '', $args{tests};
    my $tests = '-' . join (' -', @items);
    undef @items;
    $args{regex} = qr/$args{regex}/;
    opendir my $dh, $args{dir} or die "Can't opendir on $args{dir}: $!";
    while (my $item = readdir $dh) {
        if (($item !~ $args{regex}) or ($item =~ m/^\.{1,2}$/)) { next  }
        my $i = "$args{dir}/$item";
        if (not defined $i) {
            confess "\$i isn't defined.";
        }
        my $rv = eval "${tests} \$i" || 0;
        if ($rv == 0) { next }
        if ($args{dir} eq '.') {
            push @items, $item
        } else {
            push @items, $i
        }
    }
# this is the new part, and what doesn't work
    if ($args{recursive} == 1) {
        find({
            wanted => \sub {
                if ((eval "${tests} $_") && ($_ =~ /$args{regex}/)) {
                    push @items, $_;
                }
            },
            chdir => 1,
            '.'
        });
    }
    @items
}
foreach my $pl (dir(recursive => 1, regex => '\.pl$')) {
    say $pl
}

это дает ошибку:

Odd number of elements in anonymous hash at clean.pl line 44

Я думаю, что это из-за функции find внизу, как указывает ошибка.

Передача одной подпрограммы в другую подпрограмму чем-то похожа на мой вопрос, но я не вижу, как там применить к моему случаю.

Прохождение wanted => sub и wanted => \sub дает ту же ошибку.

Как я могу заставить эту wanted подпрограмму перейти к find без ошибок?

sub {...} возвращает ссылку на код; \sub {} будет ссылкой на ссылку на код, а не на то, что вы обычно хотели бы
ysth 25.12.2020 20:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
87
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Perl пытается использовать каждый нечетный аргумент в качестве хэш-ключа и каждый четный в качестве хэш-значения, поэтому с нечетным количеством аргументов вы получаете ошибку «нечетное количество аргументов», из-за которой вы помещаете все аргументы в find в анонимной хэш-ссылке. Имя файла/путь не имеет хеш-ключа, поэтому удалите его из хэш-ссылки.

Затем передайте процедуру wanted следующим образом:

wanted => sub { ... }

Тем не менее, мой File::Find знает только no_chdir, а не chdir, поэтому вы, вероятно, захотите переключить значение.

Это работает для меня:

find(
    {
        wanted => sub {
            if ((eval "${tests} $_") && ($_ =~ /$args{regex}/)) {
                push @items, $_;
            }
        },
        no_chdir => 0,
    },
    '.'    # File outside the hash ref
);

Могу добавить, что для моих целей no_chir = 1 работал лучше. Спасибо за отличное решение!

con 24.12.2020 22:23

Другие вопросы по теме