Spec-Zone.ru › Perl 5.28

autodie::hints

СОДЕРЖАНИЕ

  • ИМЯ
  • СИНТАКСИС
  • ОПИСАНИЕ
    • Введение
    • Что такое подсказки?
    • Примеры подсказок
  • Ручная настройка подсказок в вашей программе
  • Добавление подсказок в ваш модуль
  • Требование подсказок
  • Диагностика
  • БЛАГОДАРНОСТИ
  • АВТОР
  • ЛИЦЕНЗИЯ
  • СМОТРИТЕ ТАКЖЕ

ИМЯ

autodie::hints - Предоставляет подсказки о пользовательских подпрограммах для autodie

СИНТАКСИС

package Your::Module;

our %DOES = ( 'autodie::hints::provider' => 1 );

sub AUTODIE_HINTS {
    return {
        foo => { scalar => HINTS, list => SOME_HINTS },
        bar => { scalar => HINTS, list => MORE_HINTS },
    }
}

# Later, in your main program...

use Your::Module qw(foo bar);
use autodie      qw(:default foo bar);

foo();         # succeeds or dies based on scalar hints

# Alternatively, hints can be set on subroutines we've
# imported.

use autodie::hints;
use Some::Module qw(think_positive);

BEGIN {
    autodie::hints->set_hints_for(
        \&think_positive,
        {
            fail => sub { $_[0] <= 0 }
        }
    )
}
use autodie qw(think_positive);

think_positive(...);    # Returns positive or dies.

ОПИСАНИЕ

Введение

Предикат autodie очень умён, когда дело доходит до работы со встроенными функциями Perl. Поведение этих функций фиксировано, и autodie точно знает, как они пытаются сигнализировать об ошибке.

Но что насчёт пользовательских подпрограмм из модулей? Если вы используете autodie для пользовательской подпрограммы, то она предполагает следующее поведение для демонстрации ошибки:

  • Ложное значение в скалярном контексте

  • Пустой список в списочном контексте

  • Список, содержащий единственный undef, в списочном контексте

Все другие возвращаемые значения (включая список с единственной нулевой и список, содержащий единственную пустую строку) считаются успешными. Однако реальный код не всегда так прост. Возможно, код, с которым вы работаете, возвращает строку, содержащую слово «FAIL» при ошибке, или список из двух элементов, содержащих (undef, "human error message"). Чтобы заставить autodie работать с такими подпрограммами, у нас есть интерфейс подсказок.

Интерфейс подсказок позволяет предоставлять подсказки autodie о том, как она должна обнаруживать ошибки в пользовательских подпрограммах. Хотя эти подсказки могут быть предоставлены конечным пользователем autodie, их лучше всего размещать в самом модуле или в вспомогательном модуле или подклассе autodie.

Что такое подсказки?

Подсказка — это подпрограмма или значение, которое проверяется по отношению к возвращаемому значению подпрограммы autodie. Если проверка возвращает true, autodie считает, что подпрограмма завершилась ошибкой.

Если предоставленная подсказка — ссылка на подпрограмму, то autodie передаст полное возвращаемое значение этой подпрограмме. Если подсказка — любое другое значение, то autodie выполнит интеллектуальное соответствие с предоставленным значением. В Perl 5.8.x нет оператора интеллектуального соответствия, и поэтому в этих версиях поддерживаются только подсказки-подпрограммы.

Подсказки могут быть предоставлены как для скалярного, так и для списочного контекстов. Обратите внимание, что подпрограмма autodie никогда не получит пустой контекст, так как autodie всегда должна захватить возвращаемое значение для проверки. Подпрограммы autodie, вызываемые в пустом контексте, ведут себя так, как если бы они были вызваны в скалярном контексте, но их возвращаемое значение отбрасывается после проверки.

Примеры подсказок

Подсказки могут состоять из ссылок на подпрограммы, объектов, перегружающих интеллектуальное соответствие, регулярных выражений и, в зависимости от версии Perl, возможно, других вещей. Вы можете указать разные подсказки для того, как должна быть распознана ошибка в скалярном и списочном контекстах.

Эти примеры применимы к подпрограмме AUTODIE_HINTS и при вызове autodie::hints-set_hints_for()>.

Наиболее распространёнными контекстно-зависимыми подсказками являются:

# Scalar failures always return undef:
    {  scalar => sub { !defined($_[0]) }  }

# Scalar failures return any false value [default expectation]:
    {  scalar => sub { ! $_[0] }  }

# Scalar failures always return zero explicitly:
    {  scalar => sub { defined($_[0]) && $_[0] eq '0' }  }

# List failures always return an empty list:
    {  list => sub { !@_ }  }

# List failures return () or (undef) [default expectation]:
    {  list => sub { ! @_ || @_ == 1 && !defined $_[0] }  }

# List failures return () or a single false value:
    {  list => sub { ! @_ || @_ == 1 && !$_[0] }  }

# List failures return (undef, "some string")
    {  list => sub { @_ == 2 && !defined $_[0] }  }

# Unsuccessful foo() returns 'FAIL' or '_FAIL' in scalar context,
#                    returns (-1) in list context...
autodie::hints->set_hints_for(
    \&foo,
    {
        scalar => qr/^ _? FAIL $/xms,
        list   => sub { @_ == 1 && $_[0] eq -1 },
    }
);

# Unsuccessful foo() returns 0 in all contexts...
autodie::hints->set_hints_for(
    \&foo,
    {
        scalar => sub { defined($_[0]) && $_[0] == 0 },
        list   => sub { @_ == 1 && defined($_[0]) && $_[0] == 0 },
    }
);

Эта конструкция «во всех контекстах» очень распространена и может быть сокращена, используя ключевое слово «fail». Это задаёт как подсказки scalar, так и list для одного и того же значения:

# Unsuccessful foo() returns 0 in all contexts...
autodie::hints->set_hints_for(
    \&foo,
    {
        fail => sub { @_ == 1 and defined $_[0] and $_[0] == 0 }
    }
);

# Unsuccessful think_positive() returns negative number on failure...
autodie::hints->set_hints_for(
    \&think_positive,
    {
        fail => sub { $_[0] < 0 }
    }
);

# Unsuccessful my_system() returns non-zero on failure...
autodie::hints->set_hints_for(
    \&my_system,
    {
        fail => sub { $_[0] != 0 }
    }
);

Ручная настройка подсказок в вашей программе

Если вы используете модуль, который возвращает что-то особенное при ошибке, вы можете вручную создать подсказки для каждой нужной подпрограммы. После того, как подсказки заданы, они доступны для всех загруженных файлов и модулей, поэтому вы можете перенести эту работу в модуль, и он всё равно будет работать.

use Some::Module qw(foo bar);
use autodie::hints;

autodie::hints->set_hints_for(
        \&foo,
        {
                scalar => SCALAR_HINT,
                list   => LIST_HINT,
        }
);
autodie::hints->set_hints_for(
        \&bar,
        { fail => SOME_HINT, }
);

Можно передать либо ссылку на подпрограмму (рекомендуется), либо полное имя подпрограммы в качестве первого аргумента. Это означает, что вы можете задавать подсказки для модулей, которые могут загрузиться:

use autodie::hints;
autodie::hints->set_hints_for(
        'Some::Module:bar', { fail => SCALAR_HINT, }
);

Этот метод наиболее полезен, когда у вас есть проект, использующий много сторонних модулей. Вы можете определить все свои возможные подсказки в одном месте. Это может быть даже в подклассе autodie. Например:

package my::autodie;

use parent qw(autodie);
use autodie::hints;

autodie::hints->set_hints_for(...);

1;

Теперь вы можете use my::autodie, что будет работать так же, как стандартная autodie, но теперь она знает о любых подсказках, которые вы задали.

Добавление подсказок в ваш модуль

autodie предоставляет пассивный интерфейс, позволяющий объявлять подсказки для вашего модуля. Эти подсказки будут найдены и использованы autodie при загрузке, но в противном случае не имеют эффекта (или зависимостей) без autodie. Чтобы задать их, ваш модуль должен объявить, что он выполняет роль autodie::hints::provider. Это можно сделать, написав свой собственный метод DOES, используя систему, такую как Class::DOES, чтобы выполнить тяжёлую работу за вас, или объявив пакетную переменную %DOES с ключом autodie::hints::provider и соответствующим значением true.

Обратите внимание, что проверка наличия хэша %DOES — это краткая запись только для autodie. Другие модули не используют этот механизм для проверки ролей, хотя вы можете использовать модуль Class::DOES с CPAN для этого.

Кроме того, вы должны определить подпрограмму AUTODIE_HINTS, которая возвращает ссылку на хэш, содержащий подсказки для ваших подпрограмм:

package Your::Module;

# We can use the Class::DOES from the CPAN to declare adherence
# to a role.

use Class::DOES 'autodie::hints::provider' => 1;

# Alternatively, we can declare the role in %DOES.  Note that
# this is an autodie specific optimisation, although Class::DOES
# can be used to promote this to a true role declaration.

our %DOES = ( 'autodie::hints::provider' => 1 );

# Finally, we must define the hints themselves.

sub AUTODIE_HINTS {
    return {
        foo => { scalar => HINTS, list => SOME_HINTS },
        bar => { scalar => HINTS, list => MORE_HINTS },
        baz => { fail => HINTS },
    }
}

Это позволяет вашему коду задавать подсказки, не полагаясь на загрузку или установку autodie и autodie::hints. Таким образом, ваш код может действовать правильно, когда autodie установлен, но не нуждается в нём для функционирования.

Требование подсказок

Когда пользовательская подпрограмма оборачивается autodie, она будет использовать подсказки, если они доступны, а в противном случае вернётся к стандартному поведению, описанному во введении к этому документу. Это может быть проблематично, если мы ожидаем существования подсказки, но (по какой-либо причине) она не загружена.

Мы можем попросить autodie требовать использования подсказки, добавив знак восклицания в начало имени подпрограммы. Одиночный знак восклицания указывает на то, что все подпрограммы после него должны иметь объявленные подсказки.

# foo() and bar() must have their hints defined
use autodie qw( !foo !bar baz );

# Everything must have hints (recommended).
use autodie qw( ! foo bar baz );

# bar() and baz() must have their hints defined
use autodie qw( foo ! bar baz );

# Enable autodie for all of Perl's supported built-ins,
# as well as for foo(), bar() and baz().  Everything must
# have hints.
use autodie qw( ! :all foo bar baz );

Если подсказки недоступны для указанных подпрограмм, это вызовет ошибку на этапе компиляции. Требование подсказок для встроенных функций Perl (например, open и close) всегда выполняется успешно.

Требование подсказок настоятельно рекомендуется.

Диагностика

Попытка установить подсказки для неопознанной подпрограммы

Вы вызвали autodie::hints->set_hints_for() с использованием ссылки на подпрограмму, но эту ссылку нельзя было разрешить до имени подпрограммы. Это может быть анонимная подпрограмма (которую нельзя сделать autodie), или она может не иметь имени по другим причинам.

Если вы получаете эту ошибку для подпрограммы с реальным именем, то, возможно, вы нашли ошибку в autodie. См. "BUGS" в autodie для того, как сообщить об этом.

Подсказки fail не могут быть предоставлены ни скалярными, ни списочными подсказками для %s

При определении подсказок вы можете предоставить как ключевые слова list и scalar, или вы можете предоставить единственное ключевое слово fail. Смешивание этих способов не допускается.

Отсутствует подсказка %s для %s

Вы предоставили подсказку scalar без предоставления подсказки list, или наоборот. Вы должны предоставить подсказки scalar и list, или единственную подсказку fail.

БЛАГОДАРНОСТИ

  • Доктору Damian Conway за предложение интерфейса подсказок и предоставление примера использования.

  • Jacinta Richardson за перевод моих идей в эту документацию.

АВТОР

Copyright 2009, Paul Fenwick <pjf@perltraining.com.au>

ЛИЦЕНЗИЯ

Этот модуль — свободное программное обеспечение. Вы можете распространять его на тех же условиях, что и Perl.

СМОТРИТЕ ТАКЖЕ

autodie, Class::DOES

© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.28.3/autodie::hints

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API