1Type::Tiny::Manual::UsiUnsgeWritChoMnotor2i(b3u)ted PerlTyDpoec:u:mTeinntya:t:iMoannual::UsingWithMoo2(3)
2
3
4

NAME

6       Type::Tiny::Manual::UsingWithMoo2 - advanced use of Type::Tiny with Moo
7

MANUAL

9   What is a Type?
10       So far all the examples have shown you how to work with types, but we
11       haven't looked at what a type actually is.
12
13         use Types::Standard qw( Int );
14         my $type = Int;
15
16       "Int" in the above code is just a function called with zero arguments
17       which returns a blessed Perl object. It is this object that defines
18       what the Int type is and is responsible for checking values meet its
19       definition.
20
21         use Types::Standard qw( HashRef Int );
22         my $type = HashRef[Int];
23
24       The "HashRef" function, if called with no parameters returns the object
25       defining the HashRef type, just like the "Int" function did before.
26       But the difference here is that it's called with a parameter, an
27       arrayref containing the Int type object. It uses this to make the
28       HashRef[Int] type and returns that.
29
30       Like any object, you can call methods on it. The most important methods
31       to know about are:
32
33         # check the value and return a boolean
34         #
35         $type->check($value);
36
37         # return an error message about $value failing the type check
38         # but don't actually check the value
39         #
40         $type->get_message($value);
41
42         # coerce the value
43         #
44         my $coerced = $type->coerce($value);
45
46       We've already seen some other methods earlier in the tutorial.
47
48         # create a new type, same as the old type, but that has coercions
49         #
50         my $new_type = $type->plus_coercions( ... );
51
52         # different syntax for parameterized types
53         #
54         my $href = HashRef;
55         my $int = Int;
56         my $href_of_int = $href->of($int);
57
58       So now you should understand this:
59
60         use Types::Standard qw( ArrayRef Dict Optional );
61         use Types::Common::Numeric qw( PositiveInt );
62         use Types::Common::String qw( NonEmptyStr );
63
64         my $RaceInfo = Dict[
65           year    => PositiveInt,
66           race    => NonEmptyStr,
67           jockey  => Optional[NonEmptyStr],
68         ];
69
70         has latest_event  => ( is => 'rw', isa => $RaceInfo );
71         has wins          => ( is => 'rw', isa => ArrayRef[$RaceInfo] );
72         has losses        => ( is => 'rw', isa => ArrayRef[$RaceInfo] );
73
74       This can help you avoid repetition if you have a complex parameterized
75       type that you need to reuse a few times.
76
77   "where"
78       One of the most useful methods you can call on a type object is
79       "where".
80
81         use Types::Standard qw( Int );
82
83         has lucky_number => (
84           is   => 'ro',
85           isa  => Int->where(sub { $_ != 13 }),
86         );
87
88       I think you already understand what it does. It creates a new type
89       constraint on the fly, restricting the original type.
90
91       Like with coercions, these restrictions can be expressed as a coderef
92       or as a string of Perl code, operating on the $_ variable. And like
93       with coercions, using a string of code will result in better
94       performance.
95
96         use Types::Standard qw( Int );
97
98         has lucky_number => (
99           is   => 'ro',
100           isa  => Int->where(q{ $_ != 13 }),
101         );
102
103       Let's coerce a hashref of strings from an even-sized arrayref of
104       strings:
105
106         use Types::Standard qw( HashRef ArrayRef Str );
107
108         has stringhash => (
109           is   => 'ro',
110           isa  => HashRef->of(Str)->plus_coercions(
111             ArrayRef->of(Str)->where(q{ @$_ % 2 == 0 }), q{
112               my %h = @$_;
113               \%h;
114             },
115           ),
116           coerce => 1,  # never forget!
117         );
118
119       If you understand that, you really are in the advanced class.
120       Congratulations!
121
122   Unions
123       Sometimes you want to accept one thing or another thing. This is pretty
124       easy with Type::Tiny.
125
126         use Types::Standard qw( HashRef ArrayRef Str );
127
128         has strings => (
129           is    => 'ro',
130           isa   => ArrayRef[Str] | HashRef[Str],
131         );
132
133       Type::Tiny overloads the bitwise or operator so stuff like this should
134       "just work".
135
136       That said, now any code that calls "$self->strings" will probably need
137       to check if the value is an arrayref or a hashref before doing anything
138       with it. So it may be simpler overall if you just choose one of the
139       options and coerce the other one into it.
140
141   Intersections
142       Similar to a union is an intersection.
143
144         package MyAPI::Client {
145           use Moo;
146           use Types::Standard qw( HasMethods InstanceOf );
147
148           has ua => (
149             is    => 'ro',
150             isa   => (InstanceOf["MyUA"]) & (HasMethods["store_cookie"]),
151           );
152         }
153
154       Here we are checking that the UA is an instance of the MyUA class and
155       also offers the "store_cookie" method. Perhaps "store_cookie" isn't
156       provided by the MyUA class itself, but several subclasses of MyUA
157       provide it.
158
159       Intersections are not useful as often as unions are. This is because
160       they often make no sense. "(ArrayRef) & (HashRef)" would be a reference
161       which was simultaneously pointing to an array and a hash, which is
162       impossible.
163
164       Note that when using intersections, it is good practice to put
165       parentheses around each type. This is to disambiguate the meaning of
166       "&" for Perl, because Perl uses it as the bitwise and operator but also
167       as the sigil for subs.
168
169   Complements
170       For any type Foo there is a complementary type ~Foo (pronounced "not
171       Foo").
172
173         package My::Class {
174           use Moo;
175           use Types::Standard qw( ArrayRef CodeRef );
176
177           has things => ( is => 'ro', isa => ArrayRef[~CodeRef] );
178         }
179
180       "things" is now an arrayref of anything except coderefs.
181
182       If you need a number that is not an integer:
183
184         Num & ~Int
185
186       Types::Standard includes two types which are complements of each other:
187       Undef and Defined.
188
189       NegativeInt might seem to be the complement of PositiveOrZeroInt but
190       when you think about it, it is not. There are values that fall into
191       neither category, such as non-integers, non-numeric strings,
192       references, undef, etc.
193
194   "stringifies_to" and "numifies_to"
195       The Object type constraint provides "stringifies_to" and "numifies_to"
196       methods which are probably best explained by examples.
197
198       "Object->numifies_to(Int)" means any object where "0 + $object" is an
199       integer.
200
201       "Object->stringifies_to(StrMatch[$re])" means any object where
202       "$object" matches the regular expression.
203
204       "Object->stringifies_to($re)" also works as a shortcut.
205
206       "Object->numifies_to($coderef)" and "Object->stringifies_to($coderef)"
207       also work, where the coderef checks $_ and returns a boolean.
208
209       Other types which are also logically objects, such as parameterized
210       HasMethods, InstanceOf, and ConsumerOf should also provide
211       "stringifies_to" and "numifies_to" methods.
212
213       "stringifies_to" and "numifies_to" work on unions if all of the type
214       constraints in the union offer the method.
215
216       "stringifies_to" and "numifies_to" work on intersections if at least
217       one of of the type constraints in the intersection offers the method.
218
219   "with_attribute_values"
220       Another one that is probably best explained using an example:
221
222         package Horse {
223           use Types::Standard qw( Enum Object );
224
225           has gender  => (
226             is  => 'ro',
227             isa => Enum['m', 'f'],
228           );
229           has father  => (
230             is  => 'ro',
231             isa => Object->with_attribute_values(gender => Enum['m']),
232           );
233           has mother  => (
234             is  => 'ro',
235             isa => Object->with_attribute_values(gender => Enum['f']),
236           );
237         }
238
239       In this example when you set a horse's father, it will call
240       "$father->gender" and check that it matches Enum['m'].
241
242       This method is in the same family as "stringifies_as" and
243       "numifies_as", so like those, it only applies to Object and similar
244       type constraints, can work on unions/intersections under the same
245       circumstances, and will also accept coderefs and regexps.
246
247         has father  => (
248           is  => 'ro',
249           isa => Object->with_attribute_values(gender => sub { $_ eq 'm' }),
250         );
251         has mother  => (
252           is  => 'ro',
253           isa => Object->with_attribute_values(gender => qr/^f/i),
254         );
255
256       All of "stringifies_as", "numifies_as", and "with_attributes_as" are
257       really just wrappers around "where". The following two are roughly
258       equivalent:
259
260         my $type1 = Object->with_attribute_values(foo => Int, bar => Num);
261
262         my $type2 = Object->where(sub {
263           Int->check( $_->foo ) and Num->check( $_->bar )
264         });
265
266       The first will result in better performing code though.
267
268   Tied Variables
269       It is possible to tie variables to a type constraint.
270
271         use Types::Standard qw(Int);
272
273         tie my $n, Int, 4;
274
275         print "$n\n";   # says "4"
276         $n = 5;         # ok
277         $n = "foo";     # dies
278
279       This feature requires Type::Tie which is a separate thing to install.
280       Type::Tiny will automatically load Type::Tie in the background if it
281       detects you're trying to tie a variable to a type.
282
283       You can also tie arrays:
284
285         tie my @numbers, Int;
286         push @numbers, 1 .. 10;
287
288       And hashes:
289
290         tie my %numbers, Int;
291         $numbers{lucky}   = 7;
292         $numbers{unlucky} = 13;
293
294       Earlier in the manual, it was mentioned that there is a problem with
295       code like this:
296
297         push @{ $horse->children }, $non_horse;
298
299       This can be solved using tied variables.
300
301         tie @{ $horse->children }, InstanceOf["Horse"];
302
303       Here is a longer example using builders and triggers.
304
305         package Horse {
306           use Moo;
307           use Types::Standard qw( Str Num ArrayRef InstanceOf );
308           use Type::Params qw(compile);
309           use namespace::autoclean;
310
311           my $ThisClass = InstanceOf[ __PACKAGE__ ];
312
313           has name       => ( is => 'ro',    isa => Str );
314           has gender     => ( is => 'ro',    isa => Str );
315           has age        => ( is => 'rw',    isa => Num );
316           has children   => (
317             is        => 'rw',
318             isa       => ArrayRef[$ThisClass],
319             builder   => "_build_children",
320             trigger   => sub { shift->_trigger_children(@_) },
321           );
322
323           # tie a default arrayref
324           sub _build_children {
325             my $self = shift;
326             tie my @kids, $ThisClass;
327             \@kids;
328           }
329
330           # this method will tie an arrayref provided by the caller
331           sub _trigger_children {
332             my $self = shift;
333             my ($new) = @_;
334             tie @$new, $ThisClass;
335           }
336
337           sub add_child {
338             state $check = compile($ThisClass, $ThisClass);
339             my ($self, $kid) = &$check;
340             push @{ $self->children }, $kid;
341             return $self;
342           }
343         }
344
345       Now it's pretty much impossible for the caller to make a mess by adding
346       a non-horse as a child.
347

NEXT STEPS

349       Here's your next step:
350
351       •   Type::Tiny::Manual::UsingWithMoo3
352
353           There's more than one way to do it! Alternative ways of using
354           Type::Tiny, including type registries, exported functions, and
355           "dwim_type".
356

AUTHOR

358       Toby Inkster <tobyink@cpan.org>.
359
361       This software is copyright (c) 2013-2014, 2017-2021 by Toby Inkster.
362
363       This is free software; you can redistribute it and/or modify it under
364       the same terms as the Perl 5 programming language system itself.
365

DISCLAIMER OF WARRANTIES

367       THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
368       WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
369       MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
370
371
372
373perl v5.34.0                      2022-01-2T1ype::Tiny::Manual::UsingWithMoo2(3)
Impressum