lets you do things like have an error "The value you provided (20),
was not a valid rating, which must be a number from 1-10." This is
much friendlier than the default error, which just says that the value
-failed a validation check for the type.
+failed a validation check for the type. The default error can, however,
+be made more friendly by installing L<Devel::PartialDump> (version 0.14 or
+higher), which Moose will use if possible to display the invalid value.
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>.
has 'counter' => (is => 'rw', isa => PositiveInt);
This lets you use a short name rather than needing to fully qualify the name
-everywhere. It also allows you to write easily create parameterized types:
+everywhere. It also allows you to easily create parameterized types:
has 'counts' => (is => 'ro', isa => HashRef[PositiveInt]);
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.
For our example above, we might want to be more specific, and insist
that output be an object with a C<print> method:
- subtype 'CanPrint'
- => as 'Object'
- => where { $_->can('print') };
+ duck_type 'CanPrint', [qw(print)];
We can coerce file handles to an object that satisfies this condition
with a simple wrapper class:
The L<Moose::Util::TypeConstraints> module exports a number of helper
functions for creating specific kinds of types. These include
-C<class_type>, C<role_type>, and C<maybe_type>. See the docs for
-details.
+C<class_type>, C<role_type>, C<maybe_type>, and C<duck_type>. See the
+docs for details.
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>.