Примените специальную проверку (кроме типов Moose) к атрибуту Moose - PullRequest
5 голосов
/ 28 апреля 2011

Типы лосей великолепны, но иногда вам нужно быть более конкретными.Вы все знаете эти правила типа данных: этот параметр может быть только 'A', 'B' или 'C', или только символом валюты, или должен соответствовать некоторому регулярному выражению.

Посмотрите наВ следующем примере, который имеет два ограниченных атрибута, один должен быть либо 'm' или 'f', другой должен быть действительной датой ISO.Как лучше в Moose указать эти ограничения?Я бы подумал о предложении SQL CHECK, но в AFAICS нет ключевого слова check в Moose.Поэтому я использовал 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 ]

6 голосов
/ 28 апреля 2011

Просто определите свой собственный подтип и используйте его.

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;
3 голосов
/ 28 апреля 2011

Добавляя свой собственный тип, как сказал Брэд:

use Moose::Util::TypeConstraints;

my $gender_constraint = subtype as 'Str', where { $_ =~ /^[FfMm]$/ };
has gender => ( is => 'rw', isa => $gender_constraint );
0 голосов
/ 28 апреля 2011

Вы можете попробовать использовать 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$/ ]);
...