我在以下子类型和强制链中缺少什么?我希望能够强制验证类型的arrayref或死于以下输入:
-
强制字符串
-
有效字符串
-
Arrayref的混合强制和有效字符串
假设所有类型都是完全命名空间,并且未声明的函数 validate
和 coerce_str
validate(返回bool)并强制并分别从输入返回有效字符串 .
subtype 'CustomType'
=> as 'Str'
=> where { validate($_) }
;
coerce 'CustomType'
=> from 'Str'
=> via { if (my $coerced = coerce_str($_)) {
return $coerced;
}
return $_;
}
;
subtype 'ArrayRefofCustomTypes'
=> as 'ArrayRef[CustomType]'
;
coerce 'ArrayRefofCustomTypes'
=> from 'CustomType'
=> via { [ $_ ] }
;
has 'values' => ( is => 'ro', required => 1,
isa => 'ArrayRefofCustomTypes',
coerce => 1,
);
我知道CustomType有效;因为我可以定义一个属性,并使用强制字符串或已经有效的字符串初始化对象 . 我已经阅读了几次关于深度胁迫的文件(http://search.cpan.org/dist/Moose/lib/Moose/Manual/Types.pod#Deep_coercion)并且我只是不太明白我希望有人可以指出我正确的方向 . 谢谢!
在这里,我将其简化为更简洁的概述,但是:
{
package My::Class;
use strict;
use warnings;
use Moose;
use Moose::Util::TypeConstraints;
subtype 'CustomType'
=> as 'Str'
=> where { validate($_) }
;
coerce 'CustomType'
=> from 'Str'
=> via { if (my $coerced = coerce_str($_)) {
return $coerced;
}
return $_;
}
;
subtype 'ArrayRefofCustomTypes'
=> as 'ArrayRef[CustomType]'
;
coerce 'ArrayRefofCustomTypes'
=> from 'CustomType'
=> via { [ $_ ] }
;
has 'values' => ( is => 'ro', required => 1,
isa => 'ArrayRefofCustomTypes',
coerce => 1,
);
sub validate {
my $val = shift;
if ($val =~ /^\w+$/) {
return 1;
}
return ();
}
sub coerce_str {
my $val = shift;
$val =~ s/\W/_/g;
return $val;
}
}
{
package main;
use strict;
use warnings;
use Test::More qw/no_plan/;
new_ok( 'My::Class' => [ values => [ 'valid' ] ]); #ok
new_ok( 'My::Class' => [ values => [ qw/valid valid still_valid/ ] ]); #ok
new_ok( 'My::Class' => [ values => 'valid' ]); # ok
new_ok( 'My::Class' => [ values => [ 'invalid; needs some coercion - ^&%&^' ] ]); #not ok
new_ok( 'My::Class' => [ values => 'invalid; needs some coercion - ^&%&^' ]); # not ok
cmp_ok( My::Class::coerce_str('invalid; needs some coercion - ^&%&^'), 'eq', 'invalid__needs_some_coercion________', 'properly coerces strings'); #ok
}
按原样运行给出了以下内容 . 问题不是验证,而是我没有明确定义我的强制,我不确定我缺少什么:
ok 1 - The object isa My::Class
ok 2 - The object isa My::Class
ok 3 - The object isa My::Class
not ok 4 - new() died
# Failed test 'new() died'
# at testcoercion.pl line 63.
# Error was: Attribute (values) does not pass the type constraint because: Validation failed for 'ArrayRefofCustomTypes' with value [ "invalid; needs some coercion - ^&%&^" ] at C:/strawberry/perl/site/lib/Moose/Meta/Attribute.pm line 1131
<< cut >>
not ok 5 - new() died
# Failed test 'new() died'
# at testcoercion.pl line 64.
# Error was: Attribute (values) does not pass the type constraint because: Validation failed for 'ArrayRefofCustomTypes' with value "invalid; needs some coercion - ^&%&^" at C:/strawberry/perl/site/lib/Moose/Meta/Attribute.pm line 1131
<< cut >>
ok 6 - properly coerces strings
1..6
# Looks like you failed 2 tests of 6.
2 回答
你使用的一切都应该工作正常 . 例如,考虑这个测试:
这打印:
结论:如果遇到问题,可以使用其他代码 . 你能粘贴一些不能按预期工作的代码吗?
所以是的,强制需要从基类型明确定义到自定义类型,以便输入所有输入的排列 . 将强制和验证代码移出到子例程有助于防止代码重复,但不能完全消除它 . 以下代码按照我的预期运行,并附有TAP计划来证明它 .
虽然它虽然有效,但我并不完全相信它是处理这类事情的预定方式 . 它正在进行大量从基类型到arrayref自定义类型的显式转换,如果访问器接受多种带强制的类型,我不确定它在更大的上下文中的效果如何 .
编辑:实际上,此时
coerce 'ArrayRefofCustomTypes' => from 'CustomType'
完全没必要,=> from 'Str'
将处理有效和无效输入 .