Сжатый MooseX :: Объявить ошибки проверки подписи метода - PullRequest
10 голосов
/ 03 декабря 2010

Я был сторонником принятия Moose (и MooseX :: Declare) на работе в течение нескольких месяцев.Стимулируемый им стиль действительно поможет поддерживать нашу кодовую базу, но не без первоначальных затрат на изучение нового синтаксиса и особенно на изучение того, как анализировать ошибки проверки типов.

Я имеювидел обсуждение этой проблемы в Интернете и думал, что я отправлю запрос в это сообщество:

а) известные решения

б) обсуждение того, как должны выглядеть сообщения об ошибках валидации

в) предложить доказательство концепции, которая реализует некоторые идеи

Я также свяжусь с авторами, но я также видел несколько хороших обсуждений на этом форуме, поэтому я решил опубликовать что-то публичное.

#!/usr/bin/perl

use MooseX::Declare;
class Foo {

    has 'x' => (isa => 'Int', is => 'ro');

    method doit( Int $id, Str :$z, Str :$y ) {
        print "doit called with id = " . $id . "\n";
        print "z = " . $z . "\n";
        print "y = " . $y . "\n";
    }

    method bar( ) {
        $self->doit(); # 2, z => 'hello', y => 'there' );
    }
}

my $foo = Foo->new( x => 4 );
$foo->bar();

Обратите внимание на несоответствие в вызове Foo :: doit с подписью метода.

В результате появляется сообщение об ошибке:

Validation failed for 'MooseX::Types::Structured::Tuple[MooseX::Types::Structured::Tuple[Object,Int],MooseX::Types::Structured::Dict[z,MooseX::Types::Structured::Optional[Str],y,MooseX::Types::Structured::Optional[Str]]]' failed with value [ [ Foo=HASH(0x2e02dd0) ], {  } ], Internal Validation Error is: Validation failed for 'MooseX::Types::Structured::Tuple[Object,Int]' failed with value [ Foo{ x: 4 } ] at /usr/local/share/perl/5.10.0/MooseX/Method/Signatures/Meta/Method.pm line 441
 MooseX::Method::Signatures::Meta::Method::validate('MooseX::Method::Signatures::Meta::Method=HASH(0x2ed9dd0)', 'ARRAY(0x2eb8b28)') called at /usr/local/share/perl/5.10.0/MooseX/Method/Signatures/Meta/Method.pm line 145
    Foo::doit('Foo=HASH(0x2e02dd0)') called at ./type_mismatch.pl line 15
    Foo::bar('Foo=HASH(0x2e02dd0)') called at ./type_mismatch.pl line 20

Я думаю, чтобольшинство согласны с тем, что это не так прямо, как могло бы быть.Я реализовал хак в моей локальной копии MooseX :: Method :: Signatures :: Meta :: Method, который выдает этот вывод для той же программы:

Validation failed for

   '[[Object,Int],Dict[z,Optional[Str],y,Optional[Str]]]' failed with value [ [ Foo=HASH(0x1c97d48) ], {  } ]

Internal Validation Error:

   '[Object,Int]' failed with value [ Foo{ x: 4 } ]

Caller: ./type_mismatch.pl line 15 (package Foo, subroutine Foo::doit)

Супер-хакерский код, который делает этоis

    if (defined (my $msg = $self->type_constraint->validate($args, \$coerced))) {
        if( $msg =~ /MooseX::Types::Structured::/ ) {
            $msg =~ s/MooseX::Types::Structured:://g;
            $msg =~ s/,.Internal/\n\nInternal/;
            $msg =~ s/failed.for./failed for\n\n   /g;
            $msg =~ s/Tuple//g;
            $msg =~ s/ is: Validation failed for/:/;
        }
        my ($pkg, $filename, $lineno, $subroutine) = caller(1);
        $msg .= "\n\nCaller: $filename line $lineno (package $pkg, subroutine $subroutine)\n";
        die $msg;
    }

[Примечание: после нескольких минут обхода кода это выглядит как MooseX :: Meta :: TypeConstraint :: Structured :: validate немного ближе к коду, который нужно изменить,В любом случае, вопрос об идеальном сообщении об ошибке и о том, активно ли кто-то работает или думает о подобных изменениях, стоит.]

, который выполняет 3 вещи:

1) Меньше многословно, большепробел (я обсуждал, включая s / Tuple //, но пока придерживаюсь его)

2) Включая вызывающий файл / линию (с хрупким использованием вызывающей стороны (1))

3)умереть вместо признания - поскольку, на мой взгляд, главным преимуществом признания было нахождение точки входа пользователя в проверку типов в любом случае, чего мы можем достичь менее подробными способами

Конечно, я на самом деле не хочуподдержать этот патч.Мой вопрос: каков наилучший способ сбалансировать полноту и краткость этих сообщений об ошибках, и есть ли в настоящее время какие-либо планы по внедрению чего-то подобного?

Ответы [ 2 ]

10 голосов
/ 03 декабря 2010

Я рад, что тебе нравится MooseX::Declare.Однако ошибки проверки подписи метода, о которых вы говорите, на самом деле не оттуда, а от MooseX::Method::Signatures, который, в свою очередь, использует MooseX::Types::Structured для своих нужд проверки.Каждая ошибка проверки, которую вы видите в настоящее время, не изменяется с MooseX::Types::Structured.

Я также собираюсь игнорировать часть трассировки стека в сообщении об ошибке.Я нахожу их невероятно полезными, как и остальная часть клики Муз.Я не собираюсь удалять их по умолчанию.

Если вы хотите, чтобы отключить их, нужно изменить Moose, чтобы он выбрасывал объекты исключений вместо строк для ошибок проверки ограничения типа и, возможно, других вещей.Они всегда могут зафиксировать обратную трассировку, но решение о том, отображать это или нет, или как именно отформатировать его при отображении, может быть принято в другом месте, и пользователь будет свободен изменять поведение по умолчанию - глобально, локально, лексически,что угодно.

Я собираюсь рассмотреть фактические сообщения об ошибках валидации для сигнатур методов.

Как указывалось, MooseX::Types::Structured выполняет фактическую валидацию.Когда что-то не проходит проверку, его задача - создать исключение.В настоящее время это исключение является строкой, поэтому оно не очень полезно при создании красивых ошибок, поэтому его необходимо изменить, аналогично проблеме со следами стека, описанной выше.

Once MooseX :: Types ::Структурированные выбросы объектов структурированных исключений, которые могут выглядеть примерно как

bless({
    type => Tuple[Tuple[Object,Int],Dict[z,Optional[Str],y,Optional[Str]]],
    err  => [
        0 => bless({
            type => Tuple[Object,Int],
            err  => [
                0 => undef,
                1 => bless({
                    type => Int,
                    err  => bless({}, 'ValidationError::MissingValue'),
                }, 'ValidationError'),
            ],
        }, 'ValidationError::Tuple'),
        1 => undef,
    ],
}, 'ValidationError::Tuple')

. У нас будет достаточно информации, чтобы фактически соотнести отдельные внутренние ошибки проверки с частями подписи в MooseX::Method::Signatures.В приведенном выше примере и с учетом вашей подписи (Int $id, Str :$z, Str :$y) было бы достаточно просто знать, что внутренняя Validation::MissingValue для второго элемента кортежа для позиционных параметров должна была обеспечивать значение для $id, ноне может.

Учитывая это, будет легко генерировать ошибки, такие как

http://files.perldition.org/err1.png

или

http://files.perldition.org/err2.png

- это то, к чему я стремлюсь, вместо того, чтобы просто отформатировать ужасные сообщения, которые у нас есть сейчас, более красиво.Однако, если бы кто-то хотел это сделать, все равно было бы достаточно просто, если бы мы структурировали исключения проверки вместо простых строк.

Ничего из этого на самом деле не сложно - это просто нужно сделать.Если кто-то захочет помочь с этим, приходите поговорить с нами в #moose на irc.perl.org.

1 голос
/ 31 декабря 2011

Method::Signatures::Modifiers - это пакет, который надеется решить некоторые из проблем MooseX::Method::Signatures. Просто use это перегрузить.

use MooseX::Declare;
use Method::Signatures::Modifiers;

class Foo
{
    method bar (Int $thing) {
        # this method is declared with Method::Signatures instead of MooseX::Method::Signatures
    }
}
...