Provided by: libtype-tiny-perl_0.022-1_all 

NAME
Type::Tiny::Manual::Coercions - adding coercions to type constraints
DESCRIPTION
Stop! Don't do it!
OK, it's fairly common practice in Moose/Mouse code to define coercions for type constraints. For
example, suppose we have a type constraint:
class_type PathTiny, { class => "Path::Tiny" };
We may wish to define a coercion (i.e. a convertion routine) to handle strings, and convert them into
Path::Tiny objects:
coerce PathTiny,
from Str, via { "Path::Tiny"->new($_) };
However, there are good reasons to avoid this practice. It ties the coercion routine to the type
constraint. Any people wishing to use your "PathTiny" type constraint need to buy in to your idea of how
they should be coerced from "Str". With Path::Tiny this is unlikely to be controversial, however
consider:
coerce ArrayRef,
from Str, via { [split /\n/] };
In one part of the application (dealing with parsing log files for instance), this could be legitimate.
But another part (dealing with logins perhaps) might prefer to split on colons. Another (dealing with web
services) might attempt to parse the string as a JSON array.
If all these coercions have attached themselves to the "ArrayRef" type constraint, coercing a string
becomes a complicated proposition! In a large application where coercions are defined across many
different files, the application can start to suffer from "spooky action at a distance".
In the interests of Moose-compatibility, Type::Tiny and Type::Coercion do allow you to define coercions
this way, but they also provide an alternative that you should consider: "plus_coercions".
plus_coercions
Type::Tiny offers a method "plus_coercions" which constructs a new anonymous type constraint, but with
additional coercions.
In our earlier example, we'd define the "PathTiny" type constraint as before:
class_type PathTiny, { class => "Path::Tiny" };
But then not define any coercions for it. Later, when using the type constraint, we can add coercions:
my $ConfigFileType = PathTiny->plus_coercions(
Str, sub { "Path::Tiny"->new($_) },
Undef, sub { "Path::Tiny"->new("/etc/myapp/default.conf") },
);
has config_file => (
is => "ro",
isa => $ConfigFileType,
coerce => 1,
);
Where the "PathTiny" constraint is used in another part of the code, it will not see these coercions,
because they were added to the new anonymous type constraint, not to the "PathTiny" constraint itself!
Aside: Optimizing Coercions
Stepping away from the flow of this article, I'll point out that the following also works, using strings
of Perl code instead of coderefs. It allows Type::Coercion to do a little optimization and run faster:
my $ConfigFileType = PathTiny->plus_coercions(
Str, q{ "Path::Tiny"->new($_) },
Undef, q{ "Path::Tiny"->new("/etc/myapp/default.conf") },
);
Now, where were we...?
Named Coercions
A type library may define a named set of coercions to a particular type. For example, let's define that
coercion from "Str" to "ArrayRef":
declare_coercion "LinesFromStr",
to_type ArrayRef,
from Str, q{ [split /\n/] };
Now we can import that coercion using a name, and it makes our code look a little cleaner:
use Types::Standard qw(ArrayRef);
use MyApp::Types qw(LinesFromStr);
has lines => (
is => "ro",
isa => ArrayRef->plus_coercions(LinesFromStr),
coerce => 1,
);
Overloading
Type::Tiny and Type::Coercion overload the "+" operator to add coercions. So you may use:
isa => PathTiny + PathTinyFromStr,
However, beware precedence. The following is parsed as a function call with an argument preceded by a
unary plus:
isa => ArrayRef + LinesFromStr,
# ArrayRef( +LinesFromStr )
When things can be parameterized, it's generally a good idea to wrap them in parentheses to disambiguate:
isa => (ArrayRef) + LinesFromStr,
Parameterized Coercions
Parameterized type constraints are familiar from Moose. For example, an arrayref of integers:
ArrayRef[Int]
Type::Coercion supports parameterized named coercions too. For example, the following type constraint has
a coercion from strings that splits them into lines:
use Types::Standard qw( ArrayRef Split );
my $ArrayOfLines = (ArrayRef) + Split[ qr{\n} ];
The implementation of this feature is considered experimental, and the API for building parameterized
coercions is likely to change. However, the feature itself, and its surface syntax (the square brackets)
is likely to stay. So beware building your own parameterizable coercions, but don't be shy about using
the ones in Types::Standard.
plus_fallback_coercions, minus_coercions and no_coercions
Getting back to the "plus_coercions" method, there are some other methods that perform coercion maths.
"plus_fallback_coercions" is the same as "plus_coercions" but the added coercions have a lower priority
than any existing coercions.
"minus_coercions" can be given a list of type constraints that we wish to ignore coercions for. Imagine
our "PathTiny" constraint already has a coercion from "Str", then the following creates a new anonymous
type constraint without that coercion:
PathTiny->minus_coercions(Str)
"no_coercions" gives us a new type anonymous constraint without any of its parents coercions. This is
useful as a way to create a blank slate for a subsequent "plus_coercions":
PathTiny->no_coercions->plus_coercions(...)
plus_constructors
The "plus_constructors" method defined in Type::Tiny::Class is sugar for "plus_coercions". The following
two are the same:
PathTiny->plus_coercions(Str, q{ Path::Tiny->new($_) })
PathTiny->plus_constructors(Str, "new");
"Deep" Coercions
Certain parameterized type constraints can automatically acquire coercions if their parameters have
coercions. For example:
ArrayRef[ Int->plus_coercions(Num, q{int($_)}) ]
... does what you mean!
The parameterized type constraints that do this magic include the following ones from Types::Standard:
• "ScalarRef"
• "ArrayRef"
• "HashRef"
• "Map"
• "Tuple"
• "Dict"
• "Optional"
SEE ALSO
Moose::Manual::BestPractices, <http://www.catalyzed.org/2009/06/keeping-your-coercions-to-yourself.html>.
AUTHOR
Toby Inkster <tobyink@cpan.org>.
COPYRIGHT AND LICENCE
This software is copyright (c) 2013 by Toby Inkster.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5
programming language system itself.
DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
perl v5.18.1 2013-07-15 Type::Tiny::Manual::Coercions(3pm)