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