Spec-Zone.ru › Perl 5.30

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.30.3/autodie::hints

Spec-Zone.ru

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