Perl 简洁的MooseX::声明方法签名验证错误

Perl 简洁的MooseX::声明方法签名验证错误,perl,moose,Perl,Moose,几个月来,我一直支持在工作中收养驼鹿(和MooseX::Declare)。它所鼓励的风格将真正有助于代码库的可维护性,但并非没有学习新语法的初始成本,特别是在学习如何解析类型验证错误方面 我在网上看到了关于这个问题的讨论,我想我应该向这个社区发布一个查询: a) 已知解决方案 b) 讨论验证错误消息应该是什么样子 c) 提出实现某些想法的概念证明 我也会联系作者,但我在这个论坛上也看到了一些很好的讨论,所以我想我应该发布一些公开的东西 #!/usr/bin/perl use MooseX::D

几个月来,我一直支持在工作中收养驼鹿(和MooseX::Declare)。它所鼓励的风格将真正有助于代码库的可维护性,但并非没有学习新语法的初始成本,特别是在学习如何解析类型验证错误方面

我在网上看到了关于这个问题的讨论,我想我应该向这个社区发布一个查询:

a) 已知解决方案

b) 讨论验证错误消息应该是什么样子

c) 提出实现某些想法的概念证明

我也会联系作者,但我在这个论坛上也看到了一些很好的讨论,所以我想我应该发布一些公开的东西

#!/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副本中实现了一个hack,它为同一个程序生成以下输出:

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)
这样做的超级黑客代码是

    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更接近应该更改的代码。在任何情况下,关于理想错误消息的问题,以及是否有人正在积极处理或考虑类似的更改。]

它完成了三件事:

1) 更少的冗长,更多的空白(我讨论过包括s/Tuple/,但现在我坚持使用它)

2) 包括调用文件/线路(使用调用方(1))

3) 死而不是坦白——因为在我看来,坦白的主要优点是找到了用户进入类型检查的入口点,这可以通过不太冗长的方式实现


当然我并不想支持这个补丁。我的问题是:平衡这些错误消息的完整性和简洁性的最佳方法是什么?目前有没有计划将类似的内容落实到位?

我很高兴您喜欢
MooseX::Declare
。但是,该方法需要签名验证 你所说的错误并不是从那里来的,而是从那里来的
MooseX::Method::Signatures
,它反过来使用
MooseX::Types::Structured
来 需要对其进行验证。您当前看到的每个验证错误都未经修改 来自
MooseX::Types::Structured

我还将忽略错误消息的堆栈跟踪部分。我碰巧 发现它们非常有用,驼鹿集团的其他成员也是如此。我不去 默认情况下删除它们

如果您想要一种关闭它们的方法,则需要将Moose更改为抛出异常 类型约束验证错误的对象而不是字符串 其他事情。这些总是可以捕获回溯,但是 是否显示它,或者在显示时如何准确地格式化它,都可以 可以在其他地方创建,用户可以自由修改默认行为- 全球、本地、词汇,无论什么

我将要解决的是为构建实际的验证错误消息 方法签名

正如所指出的,
MooseX::Types::Structured
进行实际验证 工作当某些东西无法验证时,它的工作就是引发异常。这 异常当前恰好是一个字符串,所以当 想要构建漂亮的错误,所以需要改变,类似于这个问题 上面有堆叠痕迹

一旦MooseX::Types::Structured抛出结构化异常对象,可能 有点像

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)
签名,就很容易知道了 第二个元素的内部
验证::MissingValue
位置参数的元组应该为
$id
提供一个值,但是 不能

因此,很容易产生错误,例如

这正是我想要的,而不仅仅是格式化可怕的 我们现在收到的信息更准确。然而,如果有人想这样做,它会 一旦我们有了结构化的验证异常而不是 纯字符串

所有这些其实都不难——只是需要去做。如果有人想帮忙 说到这里,请在
irc.perl.org上的
#moose
中与我们交谈
是一个希望解决
MooseX::Method::Signatures
的一些问题的软件包。只需
使用
即可过载

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
    }
}

谢谢,那真的很有帮助。尽管现在我的问题变成了:1)抛出这样的结构化异常的Moose-y方法是什么,2)如果这太麻烦,那么将类型验证因素考虑在内,不使用异常来表示验证失败会更容易吗?无论理想的解决方案是什么,我都乐意帮助这个项目。你认为这要做多少工作?我喜欢你建议的错误消息格式。这真的会帮助像我这样的团队在MooseX::Declare中全速前进。@adamp:在MooseX::Constructor::AllErrors中创建结构化Moose异常的一个地方——这将是如何解决“Moose异常需要是对象”的另一个想法来源以更普遍的方式解决问题。@ether:谢谢你的提示。我将了解一下MooseX::Constructor::AllErrors,以了解应该如何创建和抛出这些验证错误。