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       You can also tie arrays:
280
281         tie my @numbers, Int;
282         push @numbers, 1 .. 10;
283
284       And hashes:
285
286         tie my %numbers, Int;
287         $numbers{lucky}   = 7;
288         $numbers{unlucky} = 13;
289
290       Earlier in the manual, it was mentioned that there is a problem with
291       code like this:
292
293         push @{ $horse->children }, $non_horse;
294
295       This can be solved using tied variables.
296
297         tie @{ $horse->children }, InstanceOf["Horse"];
298
299       Here is a longer example using builders and triggers.
300
301         package Horse {
302           use Moo;
303           use Types::Standard qw( Str Num ArrayRef InstanceOf );
304           use Type::Params qw( signature );
305           use namespace::autoclean;
306
307           my $ThisClass = InstanceOf[ __PACKAGE__ ];
308
309           has name       => ( is => 'ro',    isa => Str );
310           has gender     => ( is => 'ro',    isa => Str );
311           has age        => ( is => 'rw',    isa => Num );
312           has children   => (
313             is        => 'rw',
314             isa       => ArrayRef[$ThisClass],
315             builder   => "_build_children",
316             trigger   => sub { shift->_trigger_children(@_) },
317           );
318
319           # tie a default arrayref
320           sub _build_children {
321             my $self = shift;
322             tie my @kids, $ThisClass;
323             \@kids;
324           }
325
326           # this method will tie an arrayref provided by the caller
327           sub _trigger_children {
328             my $self = shift;
329             my ($new) = @_;
330             tie @$new, $ThisClass;
331           }
332
333           sub add_child {
334             state $check = signature(
335               method     => $ThisClass,
336               positional => [ $ThisClass ],
337             );
338             my ( $self, $kid ) = &$check;
339             push @{ $self->children }, $kid;
340             return $self;
341           }
342         }
343
344       Now it's pretty much impossible for the caller to make a mess by adding
345       a non-horse as a child.
346
347       (Note there's a Types::Self module on CPAN that will define a Self type
348       meaning InstanceOf[ __PACKAGE__ ] for you!)
349

NEXT STEPS

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

AUTHOR

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

DISCLAIMER OF WARRANTIES

369       THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
370       WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
371       MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
372
373
374
375perl v5.36.0                      2023-01-0T4ype::Tiny::Manual::UsingWithMoo2(3)
Impressum