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 и соответствующим истинным значением.
Обратите внимание, что проверка на %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. См. "BUGS" в autodie для того, как сообщить об этом.
- Подсказки fail не могут быть предоставлены со скалярными или списковыми подсказками для %s
-
При определении подсказок вы можете предоставить как ключевые слова
listиscalar, или вы можете предоставить одно ключевое словоfail. Вы не можете комбинировать их. - Не хватает подсказки %s для %s
-
Вы предоставили подсказку
scalarбез предоставления подсказкиlist, или наоборот. Вы должны предоставить подсказкиscalarиlist, или одну подсказкуfail.
БЛАГОДАРНОСТИ
-
Доктору Дэмиану Конвею за предложение интерфейса подсказок и предоставление примеров использования.
-
Джасинте Ричардсон за перевод моих идей в эту документацию.
АВТОР
Авторское право 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.34.0/autodie::hints