Perl 使用type::Tiny使用另一个类型参数化类型
我想基于字符串创建一个类型,它将有长度上限,也可以有长度下限。即参数化类型,其中长度范围将是一个参数。Perl 使用type::Tiny使用另一个类型参数化类型,perl,oop,moose,coercion,Perl,Oop,Moose,Coercion,我想基于字符串创建一个类型,它将有长度上限,也可以有长度下限。即参数化类型,其中长度范围将是一个参数。 我在实现中需要什么: 字符串长度范围的单独类型 不使用MooseX::Types::Parameterable 直接使用arrayref而不是hashref参数化类型的一种方法: 这:isa=>Varchar[1,15] 不是这样:isa=>Varchar[{min=>1,max=>15,}] 这就是我目前掌握的情况: 文件MyTypesTiny.pm package MyTypesT
我在实现中需要什么:
- 字符串长度范围的单独类型
- 不使用MooseX::Types::Parameterable
- 直接使用arrayref而不是hashref参数化类型的一种方法:
- 这:
isa=>Varchar[1,15]
- 不是这样:
isa=>Varchar[{min=>1,max=>15,}]
- 这:
这就是我目前掌握的情况:
文件MyTypesTiny.pm
package MyTypesTiny;
use strict;
use warnings;
use Type::Library
-base,
-declare => qw( VarcharRange Varchar );
use Type::Utils -all;
use Types::Standard -types;
use MooseX::Types::Common::Numeric qw( PositiveOrZeroInt );
declare VarcharRange,
as HashRef [PositiveOrZeroInt],
where {
return 0 if ( grep { $_ ne 'min' && $_ ne 'max' } keys %{$_} );
return ( $_->{min} <= $_->{max} )
if ( defined $_->{max} && defined $_->{min} );
return 1;
}, message { "$_" };
coerce VarcharRange, from ArrayRef [PositiveOrZeroInt], via {
my $result;
my @keys = qw(min max);
foreach my $val ( reverse @$_ ) {
my $key = pop @keys // 'bad_range';
$result->{$key} = $val;
}
return $result;
};
1;
好的,VarcharRange有效。
现在我必须添加Varchar本身。这就是我立刻陷入困境的地方:
添加到MyTypesTiny.pm:
declare Varchar, as Str, where {}, constraint_generator => sub {
# here I have @_ which is an ArrayRef
# and I want to create a VarcharRange object $range from it
# but what exactly should I do?
return sub {
my $len = length($_);
return 0 if ( $range->{min} && $len < $range->{min} );
return 0 if ( $range->{max} && $len > $range->{max} );
return 1;
};
};
package MyTypesTiny;
use Types::Standard -all;
use Type::Library -base, -declare => qw(Varchar);
use Type::Utils -all;
sub _get_varchar_args {
die "can only give 0-2 parameters" if @_ > 2;
map assert_Int($_), @_;
return @_ == 1 ? (0, @_) : @_;
}
declare "Varchar",
as Str,
constraint_generator => sub {
my ($min_length, $max_length) = _get_varchar_args(@_);
return sub {
length($_) >= $min_length and length($_) <= $max_length;
};
},
inline_generator => sub {
my ($min_length, $max_length) = _get_varchar_args(@_);
return sub {
my ($constraint, $varname) = @_;
return sprintf(
'length(%s) >= %d and length(%s) <= %d',
$varname,
$min_length,
$varname,
$max_length,
);
};
};
1;
将Varchar声明为Str,其中{},constraint_generator=>sub{
#这是一个数组ref
#我想从中创建一个VarcharRange对象$range
#但我到底该怎么办呢?
返回接头{
my$len=长度($\ux);
如果($range->{min}&$len<$range->{min}),则返回0;
如果($range->{max}&$len>$range->{max}),则返回0;
返回1;
};
};
我的大脑沸腾了。我的ArrayRef准备好了。我所需要的只是一个VarcharRange(基本上是一个HashRef)对象。但是VarcharRange是一个类型-一组约束和强制规则的名称标记集。它与对象本身不对应。类型的对象是在创建类属性时创建的,但我在这里没有任何类。这就是我最终得到的。不得不额外增加一门课。它起作用了,我可能就到此为止 字符串长度范围的类:
package VarcharRange;
use strict;
use warnings;
use Moose;
use Moose::Util::TypeConstraints;
subtype 'AuxRange', as 'HashRef[Int]', where {
foreach my $range_id ( keys %{$_} ) {
return 0 if ( $range_id ne 'min' && $range_id ne 'max' );
return 0 if ( $_->{$range_id} < 0 );
}
return ( $_->{min} <= $_->{max} )
if ( defined $_->{max} && defined $_->{min} );
return 1;
}, message {
'invalid VarcharRange'
};
coerce 'AuxRange', from 'ArrayRef[Int]', via {
my $result;
my @keys = qw(min max);
foreach my $val ( reverse @$_ ) {
my $key = pop @keys // 'bad_range';
$result->{$key} = $val;
}
return $result;
};
has range => (
isa => 'AuxRange',
traits => ['Hash'],
coerce => 1,
handles => {
'max' => [ get => 'max' ],
'min' => [ get => 'min' ],
},
);
1;
这是一个能够为“Varchar”类型提供参数的答案。启用参数化类型的神奇之处在于为类型提供一个
约束\u生成器
。此解决方案没有中间hashref,它只有一种类型
MyTypesTiny.pm:
declare Varchar, as Str, where {}, constraint_generator => sub {
# here I have @_ which is an ArrayRef
# and I want to create a VarcharRange object $range from it
# but what exactly should I do?
return sub {
my $len = length($_);
return 0 if ( $range->{min} && $len < $range->{min} );
return 0 if ( $range->{max} && $len > $range->{max} );
return 1;
};
};
package MyTypesTiny;
use Types::Standard -all;
use Type::Library -base, -declare => qw(Varchar);
use Type::Utils -all;
sub _get_varchar_args {
die "can only give 0-2 parameters" if @_ > 2;
map assert_Int($_), @_;
return @_ == 1 ? (0, @_) : @_;
}
declare "Varchar",
as Str,
constraint_generator => sub {
my ($min_length, $max_length) = _get_varchar_args(@_);
return sub {
length($_) >= $min_length and length($_) <= $max_length;
};
},
inline_generator => sub {
my ($min_length, $max_length) = _get_varchar_args(@_);
return sub {
my ($constraint, $varname) = @_;
return sprintf(
'length(%s) >= %d and length(%s) <= %d',
$varname,
$min_length,
$varname,
$max_length,
);
};
};
1;
tester.pl:
#!perl
use MyClass;
my $check = MyClass->new( my_string => 'ASDef45F%'); # length 9, ok
$check = MyClass->new( my_string => 'f45F%'); # length 5, not ok
你不会放弃吧我看不到
VarcharRange
和Varchar
之间的连接。请参阅Varchar
代码中的注释行。本质上,当我通过ArrayRef参数化Varchar
时,实际上,我想通过VarcharRange
参数化Varchar
(可以从ArrayRef强制)。然后呢?您只想验证字符串是否在该长度范围内?这些类型不是类。他们是典型的。我会这么做的。另外,not Types::Common::String(与Type::Tiny捆绑在一起)包含一个StrLength
类型,从1.004000版起,该类型就可以实现这一点。
package MyClass;
use Moo;
use MyTypesTiny -all;
has my_string => (
is => 'ro',
isa => Varchar[9, 10],
);
1;
#!perl
use MyClass;
my $check = MyClass->new( my_string => 'ASDef45F%'); # length 9, ok
$check = MyClass->new( my_string => 'f45F%'); # length 5, not ok