Spec-Zone.ru › Perl 5.38

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. См. "Ошибки" в 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–2023 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.38.0/autodie::hints

Spec-Zone.ru

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