1Type::Tiny::Manual::LibUrsaerrieCso(n3t)ributed Perl DocTuympeen:t:aTtiinoyn::Manual::Libraries(3)
2
3
4

NAME

6       Type::Tiny::Manual::Libraries - defining your own type libraries
7

MANUAL

9   Defining a Type
10       A type is an object and you can create a new one using the constructor:
11
12         use Type::Tiny;
13
14         my $type = Type::Tiny->new(%args);
15
16       A full list of the available arguments can be found in the Type::Tiny
17       documentation, but the most important ones to begin with are:
18
19       "name"
20           The name of your new type. Type::Tiny uses a convention of
21           UpperCamelCase names for type constraints. The type name may also
22           begin with one or two leading underscores to indicate a type
23           intended for internal use only.  Types using non-ASCII characters
24           may cause problems on older versions of Perl (pre-5.8).
25
26           Although this is optional and types may be anonymous, a name is
27           required for a type constraint to added to a type library.
28
29       "constraint"
30           A code reference checking $_ and returning a boolean.
31           Alternatively, a string of Perl code may be provided.
32
33           If you've been paying attention, you can probably guess that the
34           string of Perl code may result in more efficient type checks.
35
36       "parent"
37           An existing type constraint to inherit from. A value will need to
38           pass the parent constraint before its own constraint would be
39           called.
40
41             my $Even = Type::Tiny->new(
42               name       => 'EvenNumber',
43               parent     => Types::Standard::Int,
44               constraint => sub {
45                 # in this sub we don't need to check that $_ is an Int
46                 # because the parent will take care of that!
47
48                 $_ % 2 == 0
49               },
50             );
51
52           Although the "parent" is optional, it makes sense whenever possible
53           to inherit from an existing type constraint to benefit from any
54           optimizations or XS implementations they may provide.
55
56   Defining a Library
57       A library is a Perl module that exports type constraints as subs.
58       Types::Standard, Types::Common::Numeric, and Types::Common::String are
59       type libraries that are bundled with Type::Tiny.
60
61       To create a type library, create a package that inherits from
62       Type::Library.
63
64         package MyTypes {
65           use Type::Library -base;
66
67           ...; # your type definitions go here
68         }
69
70       You can add types like this:
71
72         package MyTypes {
73           use Type::Library -base;
74
75           my $Even = Type::Tiny->new(
76             name       => 'EvenNumber',
77             parent     => Types::Standard::Int,
78             constraint => sub {
79               # in this sub we don't need to check that $_ is an Int
80               # because the parent will take care of that!
81
82               $_ % 2 == 0
83             },
84           );
85
86           __PACKAGE__->add_type($Even);
87         }
88
89       There is a shortcut for adding types if they're going to be blessed
90       Type::Tiny objects and not, for example, a subclass of Type::Tiny.  You
91       can just pass %args directly to "add_type".
92
93         package MyTypes {
94           use Type::Library -base;
95
96           __PACKAGE__->add_type(
97             name       => 'EvenNumber',
98             parent     => Types::Standard::Int,
99             constraint => sub {
100               # in this sub we don't need to check that $_ is an Int
101               # because the parent will take care of that!
102
103               $_ % 2 == 0
104             },
105           );
106         }
107
108       The "add_type" method returns the type it just added, so it can be
109       stored in a variable.
110
111         my $Even = __PACKAGE__->add_type(...);
112
113       This can be useful if you wish to use $Even as the parent type to some
114       other type you're going to define later.
115
116       Here's a bigger worked example:
117
118         package Example::Types {
119           use Type::Library -base;
120           use Types::Standard -types;
121           use DateTime;
122
123           # Type::Tiny::Class is a subclass of Type::Tiny for creating
124           # InstanceOf-like types. It's kind of better though because
125           # it does cool stuff like pass through $type->new(%args) to
126           # the class's constructor.
127           #
128           my $dt = __PACKAGE__->add_type(
129             Type::Tiny::Class->new(
130               name    => 'Datetime',
131               class   => 'DateTime',
132             )
133           );
134
135           my $dth = __PACKAGE__->add_type(
136             name    => 'DatetimeHash',
137             parent  => Dict[
138               year       => Int,
139               month      => Optional[ Int ],
140               day        => Optional[ Int ],
141               hour       => Optional[ Int ],
142               minute     => Optional[ Int ],
143               second     => Optional[ Int ],
144               nanosecond => Optional[ Int ],
145               time_zone  => Optional[ Str ],
146             ],
147           );
148
149           my $eph = __PACKAGE__->add_type(
150             name    => 'EpochHash',
151             parent  => Dict[ epoch => Int ],
152           );
153
154           # Can't just use "plus_coercions" method because that creates
155           # a new anonymous child type to add the coercions to. We want
156           # to add them to the type which exists in this library.
157           #
158           $dt->coercion->add_type_coercions(
159             Int,    q{ DateTime->from_epoch(epoch => $_) },
160             Undef,  q{ DateTime->now() },
161             $dth,   q{ DateTime->new(%$_) },
162             $eph,   q{ DateTime->from_epoch(%$_) },
163           );
164
165           __PACKAGE__->make_immutable;
166         }
167
168       "make_immutable" freezes to coercions of all the types in the package,
169       so no outside code can tamper with the coercions, and allows Type::Tiny
170       to make optimizations to the coercions, knowing they won't later be
171       altered. You should always do this at the end.
172
173       The library will export types Datetime, DatetimeHash, and EpochHash.
174       The Datetime type will have coercions from Int, Undef, DatetimeHash,
175       and EpochHash.
176
177   Extending Libraries
178       Type::Utils provides a helpful function "extends".
179
180         package My::Types {
181           use Type::Library -base;
182           use Type::Utils qw( extends );
183
184           BEGIN { extends("Types::Standard") };
185
186           # define your own types here
187         }
188
189       The "extends" function (which you should usually use in a "BEGIN { }"
190       block not only loads another type library, but it also adds all the
191       types from it to your library.
192
193       This means code using the above My::Types doesn't need to do:
194
195         use Types::Standard qw( Str );
196         use My::Types qw( Something );
197
198       It can just do:
199
200         use My::Types qw( Str Something );
201
202       Because all the types from Types::Standard have been copied across into
203       My::Types and are also available there.
204
205       "extends" can be passed a list of libraries; you can inherit from
206       multiple existing libraries. It can also recognize and import types
207       from MooseX::Types, MouseX::Types, and Specio::Exporter libraries.
208
209   Custom Error Messages
210       A type constraint can have custom error messages. It's pretty simple:
211
212         Type::Tiny->new(
213           name       => 'EvenNumber',
214           parent     => Types::Standard::Int,
215           constraint => sub {
216             # in this sub we don't need to check that $_ is an Int
217             # because the parent will take care of that!
218
219             $_ % 2 == 0
220           },
221           message   => sub {
222             sprintf '%s is not an even number', Type::Tiny::_dd($_);
223           },
224         );
225
226       The message coderef just takes a value in $_ and returns a string.  It
227       may use "Type::Tiny::_dd()" as a way of pretty-printing a value.
228       (Don't be put off by the underscore in the function name. "_dd()" is an
229       officially supported part of Type::Tiny's API now.)
230
231       You don't have to use "_dd()". You can generate any error string you
232       like. But "_dd()" will help you make undef and the empty string look
233       different, and will pretty-print references, and so on.
234
235       There's no need to supply an error message coderef unless you really
236       want custom error messages. The default sub should be reasonable.
237
238   Inlining
239       In Perl, sub calls are relatively expensive in terms of memory and CPU
240       use.  The PositiveInt type inherits from Int which inherits from Num
241       which inherits from Str which inherits from Defined which inherits from
242       Item which inherits from Any.
243
244       So you might think that to check of $value is a PositiveInt, it needs
245       to be checked all the way up the inheritance chain. But this is where
246       one of Type::Tiny's big optimizations happens. Type::Tiny can glue
247       together a bunch of checks with a stringy eval, and get a single
248       coderef that can do all the checks in one go.
249
250       This is why when Type::Tiny gives you a choice of using a coderef or a
251       string of Perl code, you should usually choose the string of Perl code.
252       A single coderef can "break the chain".
253
254       But these automatically generated strings of Perl code are not always
255       as efficient as they could be. For example, imagine that HashRef is
256       defined as:
257
258         my $Defined = Type::Tiny->new(
259           name       => 'Defined',
260           constraint => 'defined($_)',
261         );
262         my $Ref = Type::Tiny->new(
263           name       => 'Ref',
264           parent     => $Defined,
265           constraint => 'ref($_)',
266         );
267         my $HashRef = Type::Tiny->new(
268           name       => 'HashRef',
269           parent     => $Ref,
270           constraint => 'ref($_) eq "HASH"',
271         );
272
273       Then the combined check is:
274
275         defined($_) and ref($_) and ref($_) eq "HASH"
276
277       Actually in practice it's even more complicated, because Type::Tiny
278       needs to localize and set $_ first.
279
280       But in practice, the following should be a sufficient check:
281
282         ref($_) eq "HASH"
283
284       It is possible for the HashRef type to have more control over the
285       string of code generated.
286
287         my $HashRef = Type::Tiny->new(
288           name       => 'HashRef',
289           parent     => $Ref,
290           constraint => 'ref($_) eq "HASH"',
291           inlined    => sub {
292             my $varname = pop;
293             sprintf 'ref(%s) eq "HASH"', $varname;
294           },
295         );
296
297       The inlined coderef gets passed the name of a variable to check. This
298       could be '$_' or '$var' or "$some{deep}{thing}[0]". Because it is
299       passed the name of a variable to check, instead of always checking $_,
300       this enables very efficient checking for parameterized types.
301
302       Although in this case, the inlining coderef is just returning a string,
303       technically it returns a list of strings. If there's multiple strings,
304       Type::Tiny will join them together in a big "&&" statement.
305
306       As a special case, if the first item in the returned list of strings is
307       undef, then Type::Tiny will substitute the parent type constraint's
308       inlined string in its place. So an inlieing coderef for even numbers
309       might be:
310
311         Type::Tiny->new(
312           name       => 'EvenNumber',
313           parent     => Types::Standard::Int,
314           constraint => sub { $_ % 2 == 0 },
315           inlined    => sub {
316             my $varname = pop;
317             return (undef, "$varname % 2 == 0");
318           },
319         );
320
321       Even if you provide a coderef as a string, an inlining coderef has the
322       potential to generate more efficient code, so you should consider
323       providing one.
324
325   Parameterizable Types
326       This is probably the most "meta" concept that is going to be covered.
327       Building your own type constraint that can be parameterized like
328       ArrayRef or HasMethods.
329
330       The type constraint we'll build will be MultipleOf[$i] which checks
331       that an integer is a multiple of $i.
332
333         __PACKAGE__->add_type(
334           name       => 'MultipleOf',
335           parent     => Int,
336
337           # This coderef gets passed the contents of the square brackets.
338           constraint_generator => sub {
339             my $i = assert_Int(shift);
340             # needs to return a coderef to use as a constraint for the
341             # parameterized type
342             return sub { $_ % $i == 0 };
343           },
344
345           # optional but recommended
346           inline_generator => sub {
347             my $i = shift;
348             return sub {
349               my $varname = pop;
350               return (undef, "$varname % $i == 0");
351             };
352           },
353
354           # probably the most complex bit
355           coercion_generator => sub {
356             my $i = $_[2];
357             require Type::Coercion;
358             return Type::Coercion->new(
359               type_coercion_map => [
360                 Num, qq{ int($i * int(\$_/$i)) }
361               ],
362             );
363           },
364         );
365
366       Now we can define an even number like this:
367
368         __PACKAGE__->add_type(
369           name     => 'EvenNumber',
370           parent   => __PACKAGE__->get_type('MultipleOf')->of(2),
371           coercion => 1,  # inherit from parent
372         );
373
374       Note that it is possible for a type constraint to have a "constraint"
375       and a "constraint_generator".
376
377         BaseType          # uses the constraint
378         BaseType[]        # constraint_generator with no arguments
379         BaseType[$x]      # constraint_generator with an argument
380
381       In the MultipleOf example above, MultipleOf[] with no number would
382       throw an error because of "assert_Int(shift)" not finding an integer.
383
384       But it is certainly possible for BaseType[] to be meaningful and
385       distinct from "BaseType".
386
387       For example, Tuple is just the same as ArrayRef and accepts any
388       arrayref as being valid. But Tuple[] will only accept arrayrefs with
389       zero elements in them. (Just like Tuple[Any,Any] will only accept
390       arrayrefs with two elements.)
391

NEXT STEPS

393       After that last example, probably have a little lie down. Once you're
394       recovered, here's your next step:
395
396       ยท   Type::Tiny::Manual::UsingWithMoose
397
398           How to use Type::Tiny with Moose, including the advantages of
399           Type::Tiny over built-in type constraints, and Moose-specific
400           features.
401

AUTHOR

403       Toby Inkster <tobyink@cpan.org>.
404
406       This software is copyright (c) 2013-2014, 2017-2020 by Toby Inkster.
407
408       This is free software; you can redistribute it and/or modify it under
409       the same terms as the Perl 5 programming language system itself.
410

DISCLAIMER OF WARRANTIES

412       THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
413       WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
414       MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
415
416
417
418perl v5.30.1                      2020-02-12  Type::Tiny::Manual::Libraries(3)
Impressum