1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
=pod
=encoding utf-8
=head1 NAME
Type::Tiny::Manual::UsingWithMouse - how to use Type::Tiny with Mouse
=head1 MANUAL
First read L<Type::Tiny::Manual::Moo>, L<Type::Tiny::Manual::Moo2>, and
L<Type::Tiny::Manual::Moo3>. Everything in those parts of the manual
should work exactly the same in Mouse.
This part of the manual will focus on Mouse-specifics.
Overall, Type::Tiny is less well-tested with Mouse than it is with
Moose and Moo, but there are still a good number of test cases for
using Type::Tiny with Mouse, and there are no known major issues
with Type::Tiny's Mouse support.
=head2 Why Use Type::Tiny At All?
Mouse does have a built-in type constraint system which is fairly
convenient to use, but there are several reasons you should consider
using Type::Tiny instead.
=over
=item *
Type::Tiny provides helpful methods like C<where> and C<plus_coercions>
that allow type constraints and coercions to be easily tweaked on a
per-attribute basis.
Something like this is much harder to do with plain Mouse types:
has name => (
is => "ro",
isa => Str->plus_coercions(
ArrayRef[Str], sub { join " ", @$_ },
),
coerce => 1,
);
Mouse tends to encourage defining coercions globally, so if you wanted
one B<Str> attribute to be able to coerce from B<< ArrayRef[Str] >>, then
I<all> B<Str> attributes would coerce from B<< ArrayRef[Str] >>, and they'd
all do that coercion in the same way. (Even if it might make sense to
join by a space in some places, a comma in others, and a line break in
others!)
=item *
Type::Tiny provides automatic deep coercions, so if type B<Xyz> has a coercion,
the following should "just work":
has xyzlist => ( is => 'ro', isa => ArrayRef[Xyz], coerce => 1 );
=item *
Type::Tiny offers a wider selection of built-in types.
=item *
By using Type::Tiny, you can use the same type constraints and coercions
for attributes and method parameters, in Mouse and non-Mouse code.
=back
=head2 Type::Utils
If you've used L<Mouse::Util::TypeConstraints>, you may be accustomed to
using a DSL for declaring type constraints:
use Mouse::Util::TypeConstraints;
subtype 'Natural',
as 'Int',
where { $_ > 0 };
There's a module called L<Type::Utils> that provides a very similar DSL for
declaring types in Type::Library-based type libraries.
package My::Types {
use Type::Library -base;
use Type::Utils;
use Types::Standard qw( Int );
declare 'Natural',
as Int,
where { $_ > 0 };
}
Personally I prefer the more object-oriented way to declare types though.
In Mouse you might also declare types like this within classes and roles too.
Unlike Mouse, Type::Tiny doesn't keep types in a single global flat namespace,
so this doesn't work quite the same with Type::Utils. It still creates the
type, but it doesn't store it in any type library; the type is returned.
package My::Class {
use Mouse;
use Type::Utils;
use Types::Standard qw( Int );
my $Natural = # store type in a variable
declare 'Natural',
as Int,
where { $_ > 0 };
has number => ( is => 'ro', isa => $Natural );
}
But really, isn't the object-oriented way cleaner?
package My::Class {
use Mouse;
use Types::Standard qw( Int );
has number => (
is => 'ro',
isa => Int->where('$_ > 0'),
);
}
=head2 Type::Tiny and MouseX::Types
L<Types::Standard> should be a drop-in replacement for L<MooseX::Types>.
And L<Types::Common::Numeric> and L<Types::Common::String> should easily
replace L<MouseX::Types::Common::Numeric> and L<MouseX::Types::Common::String>.
That said, if you do with to use a mixture of Type::Tiny and MouseX::Types,
they should fit together pretty seamlessly.
use Types::Standard qw( ArrayRef );
use MouseX::Types::Mouse qw( Int );
# this should just work
my $list_of_nums = ArrayRef[Int];
# and this
my $list_or_num = ArrayRef | Int;
=head2 C<< -mouse >> Import Parameter
If you have read this far in the manual, you will know that this is the
usual way to import type constraints:
use Types::Standard qw( Int );
And the C<Int> which is imported is a function that takes no arguments and
returns the B<Int> type constraint, which is a blessed object in the
L<Type::Tiny> class.
Type::Tiny mocks the L<Mouse::Meta::TypeConstraint> API so well that most
Mouse and MouseX code will not be able to tell the difference.
But what if you need a real Mouse::Meta::TypeConstraint object?
use Types::Standard -mouse, qw( Int );
Now the C<Int> function imported will return a genuine native Mouse type
constraint.
This flag is mostly a throwback from when Type::Tiny native objects
I<< didn't >> directly work in Mouse. In 99.9% of cases, there is no
reason to use it and plenty of reasons not to. (Mouse native type
constraints don't offer helpful methods like C<plus_coercions> and
C<where>.)
=head2 C<< mouse_type >> Method
Another quick way to get a native Mouse type constraint object from a
Type::Tiny object is to call the C<mouse_type> method:
use Types::Standard qw( Int );
my $tiny_type = Int;
my $mouse_type = $tiny_type->mouse_type;
Internally, this is what the C<< -mouse >> flag makes imported functions
do.
=head2 Type::Tiny Performance
Type::Tiny should run pretty much as fast as Mouse types do. This is
because, when possible, it will use Mouse's XS implementations of type
checks to do the heavy lifting.
There are a few type constraints where Type::Tiny prefers to do things
without Mouse's help though, for consistency and correctness. For example,
the Mouse XS implementation of B<Bool> is... strange... it accepts blessed
objects that overload C<bool>, but only if they return false. If they return
true, it's a type constraint error.
Using Type::Tiny instead of Mouse's type constraints shouldn't make a
significant difference to the performance of your code.
=head1 NEXT STEPS
Here's your next step:
=over
=item * L<Type::Tiny::Manual::UsingWithMite>
How to use Type::Tiny with Mite, including how to write an entire Perl
project using clean Moose-like code and no non-core dependencies.
(Not even dependencies on Mite or Type::Tiny!)
=back
=head1 AUTHOR
Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
=head1 COPYRIGHT AND LICENCE
This software is copyright (c) 2013-2014, 2017-2023 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.
=head1 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.
=cut
|