将特定检查(超出Moose类型)应用于Moose属性

时间:2011-04-28 17:30:42

标签: perl moose

Moose types很棒,但有时你需要更具体。您都知道这些数据类型规则:该参数可能只是'A''B''C',或者只是货币符号,或者必须符合某些正则表达式。

请查看以下示例,该示例具有两个约束属性,一个必须是'm''f',另一个必须是有效的ISO日期。 Moose指定这些约束的最佳方法是什么?我想到了SQL CHECK子句,但是AFAICS在Moose中没有check个关键字。所以我使用trigger,但听起来不对。有人有更好的答案吗?

package Person;
use Moose;

has gender          => is => 'rw', isa => 'Str', trigger =>
    sub { confess 'either m or f' if $_[1] !~ m/^m|f$/ };
has name            => is => 'rw', isa => 'Str';
has dateOfBirth     => is => 'rw', isa => 'Str', trigger =>
    sub { confess 'not an ISO date' if $_[1] !~ m/^\d\d\d\d-\d\d-\d\d$/ };

no Moose;
__PACKAGE__->meta->make_immutable;

package main;
use Test::More;
use Test::Exception;

dies_ok { Person->new( gender => 42 ) } 'gender must be m or f';
dies_ok { Person->new( dateOfBirth => 42 ) } 'must be an ISO date';

done_testing;

以下是我最终使用的内容:

package Blabla::Customer;
use Moose::Util::TypeConstraints;
use Moose;

subtype ISODate => as 'Str' => where { /^\d\d\d\d-\d\d-\d\d$/ };

has id              => is => 'rw', isa => 'Str';
has gender          => is => 'rw', isa => enum ['m', 'f'];
has firstname       => is => 'rw', isa => 'Str';
has dateOfBirth     => is => 'rw', isa => 'ISODate';

no Moose;
__PACKAGE__->meta->make_immutable;

如果重要的话,这是Moose版本1.19。对于我错误地引入的错误的 subtype as => 'Str', where => { ... }语法,我收到了以下警告:Calling subtype() with a simple list of parameters is deprecated。所以我不得不根据精细的手册改变它。

3 个答案:

答案 0 :(得分:6)

只需定义自己的子类型,然后使用它。

package Person;

use Moose::Util::TypeConstraints;

use namespace::clean;
use Moose;

has gender => (
  is => 'rw',
  isa => subtype(
    as 'Str',
    where { /^[mf]$/ }
  ),
);
has name => (
  is => 'rw',
  isa => 'Str'
);
has dateOfBirth => (
  is => 'rw',
  isa => subtype(
    as 'Str',
    where { /^\d\d\d\d-\d\d-\d\d$/ }
  ),
);

no Moose;
__PACKAGE__->meta->make_immutable;
1;
package main;
use Test::More;
use Test::Exception;

dies_ok { Person->new( gender => 42 ) } 'gender must be m or f';
dies_ok { Person->new( dateOfBirth => 42 ) } 'must be an ISO date';

done_testing;

或者您可以使用MooseX::Types模块。

package Person::TypeConstraints;

use MooseX::Types::Moose qw'Str';
use MooseX::Types -declare => [qw'
  Gender ISODate
'];

subtype Gender, (
  as Str,
  where { /^[mf]$/ },
);

subtype ISODate, (
  as Str,
  where { /^\d\d\d\d-\d\d-\d\d$/ }
);
1;
package Person:

use MooseX::Types::Moose qw'Str';
use Person::TypeConstraints qw'Gender ISODate';

use namespace::clean;
use Moose;

has gender => (
  is => 'rw',
  isa => Gender,
);
has name => (
  is => 'rw',
  isa => Str,
);
has dateOfBirth => (
  is => 'rw',
  isa => ISODate,
);

no Moose;
__PACKAGE__->meta->make_immutable;
1;

答案 1 :(得分:3)

像布拉德那样添加你自己的类型:

use Moose::Util::TypeConstraints;

my $gender_constraint = subtype as 'Str', where { $_ =~ /^[FfMm]$/ };
has gender => ( is => 'rw', isa => $gender_constraint );

答案 2 :(得分:0)

您可以尝试使用MooseX-Types-Parameterizable来实现为您呈现的案例设置参数的类型(未经测试,仅绘制草图):

package YourTypes;
use MooseX::Types -declare => [qw( OneOfStr MatchingStr )];
use MooseX::Types::Moose qw( Str ArrayRef RegexpRef );

subtype OneOfStr,
     as Parameterizable[ Str, ArrayRef[ Str ] ],
     where {
         my ($str, $allowed) = @_;
         return scalar grep { $_ eq $str } @$allowed;
     };

subtype MatchingStr,
     as Parameterizable[ Str, RegexpRef ],
     where {
         my ($str, $rx) = @_;
         return scalar $str =~ $rx;
     };

1;

你会像这样使用它:

use YourTypes qw( OneOfStr MatchingStr );

has gender => (is => 'ro', isa => OneOfStr[ [qw( f m )] ]);
has dob    => (is => 'ro', isa => MatchingStr[ qr/^$yourregex$/ ]);