Moose types are great, but sometimes you need to be more specific. You all know these data type rules: that parameter may only be 'A'
, 'B'
or 'C'
, or only a currency symbol, or must conform to some regular expression.
Take a look at the following example which has two constrained attributes, one must be either 'm'
or 'f'
, the other must be a valid ISO date. What's the best way in Moose to specify these constraints? I'd think of the SQL CHECK
clause, but AFAICS there is no check
keyword in Moose. So I used trigger
, but it sounds wrong. Anyone has a better answer?
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;
Here's what I wound up using:
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;
This is Moose version 1.19, in case it matters. I got the following warning for the wrong subtype as => 'Str', where => { ... }
syntax I erroneously introduced: Calling subtype() with a simple list of parameters is deprecated
. So I had to change it a bit according to the fine manual.
Just define your own subtype, and use that.
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;
Or you could use the MooseX::Types module.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With