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 никогда не получит контекст void, поскольку autodie всегда должна захватить возвращаемое значение для проверки. Подпрограммы с autodie, вызванные в контексте void, ведут себя так, как будто они вызываются в скалярном контексте, но их возвращаемое значение отбрасывается после проверки.
Примеры подсказок
Подсказки могут состоять из ссылок на подпрограммы, объектов, перегружающих интеллектуальное сопоставление, регулярных выражений и, в зависимости от версии 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. См. "ОШИБКИ" в autodie для того, как сообщить об этом.
- Подсказки fail не могут быть предоставлены ни со скалярными, ни со списочными подсказками для %s
-
При определении подсказок вы можете предоставить как ключи
listиscalar, или вы можете предоставить единственный ключfail. Вы не можете смешивать и сопоставлять их. - Подсказка %s отсутствует для %s
-
Вы предоставили подсказку
scalarбез предоставления подсказкиlist, или наоборот. Вы должны предоставить подсказкиscalarиlist, или одну подсказкуfail.
БЛАГОДАРНОСТИ
-
Доктору Дамиану Конвею за предложение интерфейса подсказок и предоставление примеров использования.
-
Джацинте Ричардсон за перевод большей части моих идей в эту документацию.
АВТОР
Авторское право 2009, Пол Фенвик <pjf@perltraining.com.au>
ЛИЦЕНЗИЯ
Этот модуль — свободное программное обеспечение. Вы можете распространять его на тех же условиях, что и Perl сам по себе.
СМОТРИТЕ ТАКЖЕ
© 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.32.0/autodie::hints