Here's a simple (and useful) subtype example:
- subtype 'PositiveInt'
- => as 'Int'
- => where { $_ > 0 }
- => message { "The number you provided, $_, was not a positive number" }
+ subtype 'PositiveInt',
+ as 'Int',
+ where { $_ > 0 },
+ message { "The number you provided, $_, was not a positive number" };
Note that the sugar functions for working with types are all exported
by L<Moose::Util::TypeConstraints>.
A coercion lets you tell Moose to automatically convert one type to another.
- subtype 'ArrayRefOfInts'
- => as 'ArrayRef[Int]';
+ subtype 'ArrayRefOfInts',
+ as 'ArrayRef[Int]';
- coerce 'ArrayRefOfInts'
- => from 'Int'
- => via { [ $_ ] };
+ coerce 'ArrayRefOfInts',
+ from 'Int',
+ via { [ $_ ] };
You'll note that we created a subtype rather than coercing C<ArrayRef[Int]>
directly. It's a bad idea to add coercions to the raw built in
Deep coercion is the coercion of type parameters for parameterized
types. Let's take these types as an example:
- subtype 'HexNum'
- => as 'Str'
- => where { /[a-f0-9]/i };
+ subtype 'HexNum',
+ as 'Str',
+ where { /[a-f0-9]/i };
- coerce 'Int'
- => from 'HexNum'
- => via { hex $_ };
+ coerce 'Int',
+ from 'HexNum',
+ via { hex $_ };
has 'sizes' => (
is => 'ro',
However, you can define a set of subtypes to enable coercion between
two parameterized types.
- subtype 'ArrayRefOfHexNums'
- => as 'ArrayRef[HexNum]';
+ subtype 'ArrayRefOfHexNums',
+ as 'ArrayRef[HexNum]';
- subtype 'ArrayRefOfInts'
- => as 'ArrayRef[Int]';
+ subtype 'ArrayRefOfInts',
+ as 'ArrayRef[Int]';
- coerce 'ArrayRefOfInts'
- => from 'ArrayRefOfHexNums'
- => via { [ map { hex } @{$_} ] };
+ coerce 'ArrayRefOfInts',
+ from 'ArrayRefOfHexNums',
+ via { [ map { hex } @{$_} ] };
Foo->new( sizes => [ 'a1', 'ff', '22' ] );
coerce a single hex number. To do that, we need to define a separate
coercion:
- coerce 'ArrayRefOfInts'
- => from 'HexNum'
- => via { [ hex $_ ] };
+ coerce 'ArrayRefOfInts',
+ from 'HexNum',
+ via { [ hex $_ ] };
Yes, this can all get verbose, but coercion is tricky magic, and we
think it's best to make it explicit.
One helper worth noting is C<enum>, which allows you to create a
subtype of C<Str> that only allows the specified values:
- enum 'RGB' => qw( red green blue );
+ enum 'RGB', [qw( red green blue )];
This creates a type named C<RGB>.
use Moose::Util::TypeConstraints;
- subtype 'Natural'
- => as 'Int'
- => where { $_ > 0 };
+ subtype 'Natural',
+ as 'Int',
+ where { $_ > 0 };
- subtype 'NaturalLessThanTen'
- => as 'Natural'
- => where { $_ < 10 }
- => message { "This number ($_) is not less than ten!" };
+ subtype 'NaturalLessThanTen',
+ as 'Natural',
+ where { $_ < 10 },
+ message { "This number ($_) is not less than ten!" };
- coerce 'Num'
- => from 'Str'
- => via { 0+$_ };
+ coerce 'Num',
+ from 'Str',
+ via { 0+$_ };
- enum 'RGBColors' => qw(red green blue);
+ enum 'RGBColors', [qw(red green blue)];
no Moose::Util::TypeConstraints;
yet to have been created, is to quote the type name:
use DateTime;
- subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
+ subtype 'DateTime', as 'Object', where { $_->isa('DateTime') };
=head2 Default Type Constraints
L<Declare::Constraints::Simple> to declare a completely new type.
type 'HashOfArrayOfObjects',
- {
- where => IsHashRef(
- -keys => HasLength,
- -values => IsArrayRef(IsObject)
- )
- };
+ where {
+ IsHashRef(
+ -keys => HasLength,
+ -values => IsArrayRef(IsObject)
+ )->(@_);
+ };
For more examples see the F<t/200_examples/004_example_w_DCS.t> test
file.
Here is an example of using L<Test::Deep> and it's non-test
related C<eq_deeply> function.
- type 'ArrayOfHashOfBarsAndRandomNumbers'
- => where {
+ type 'ArrayOfHashOfBarsAndRandomNumbers',
+ where {
eq_deeply($_,
array_each(subhashof({
bar => isa('Bar'),
=over 4
-=item B<< subtype 'Name' => as 'Parent' => where { } ... >>
+=item B<< subtype 'Name', as 'Parent', where { } ... >>
This creates a named subtype.
The valid hashref keys are C<as> (the parent), C<where>, C<message>,
and C<optimize_as>.
-=item B<< subtype as 'Parent' => where { } ... >>
+=item B<< subtype as 'Parent', where { } ... >>
This creates an unnamed subtype and will return the type
constraint meta-object, which will be an instance of
All the built in types use this, so your subtypes (assuming they
are shallow) will not likely need to use this.
-=item B<< type 'Name' => where { } ... >>
+=item B<< type 'Name', where { } ... >>
This creates a base type, which has no parent.
=over 4
-=item B<< coerce 'Name' => from 'OtherName' => via { ... } >>
+=item B<< coerce 'Name', from 'OtherName', via { ... } >>
This defines a coercion from one type to another. The C<Name> argument
is the type you are coercing I<to>.
To define multiple coercions, supply more sets of from/via pairs:
- coerce 'Name' =>
- from 'OtherName' => via { ... },
- from 'ThirdName' => via { ... };
+ coerce 'Name',
+ from 'OtherName', via { ... },
+ from 'ThirdName', via { ... };
=item B<from 'OtherName'>