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   Pre-Declaring Types
326         use Type::Library -base,
327           -declare => qw( Foo Bar Baz );
328
329       This declares types Foo, Bar, and Baz at compile time so they can
330       safely be used as barewords in your type library.
331
332       This also allows recursively defined types to (mostly) work!
333
334         use Type::Library -base,
335           -declare => qw( NumericArrayRef );
336         use Types::Standard qw( Num ArrayRef );
337
338         __PACKAGE__->add_type(
339           name     => NumericArrayRef,
340           parent   => ArrayRef->of( Num | NumericArrayRef ),
341         );
342
343       (Support for recursive type definitions added in Type::Library
344       1.009_000.)
345
346   Parameterizable Types
347       This is probably the most "meta" concept that is going to be covered.
348       Building your own type constraint that can be parameterized like
349       ArrayRef or HasMethods.
350
351       The type constraint we'll build will be MultipleOf[$i] which checks
352       that an integer is a multiple of $i.
353
354         __PACKAGE__->add_type(
355           name       => 'MultipleOf',
356           parent     => Int,
357
358           # This coderef gets passed the contents of the square brackets.
359           constraint_generator => sub {
360             my $i = assert_Int(shift);
361             # needs to return a coderef to use as a constraint for the
362             # parameterized type
363             return sub { $_ % $i == 0 };
364           },
365
366           # optional but recommended
367           inline_generator => sub {
368             my $i = shift;
369             return sub {
370               my $varname = pop;
371               return (undef, "$varname % $i == 0");
372             };
373           },
374
375           # probably the most complex bit
376           coercion_generator => sub {
377             my $i = $_[2];
378             require Type::Coercion;
379             return Type::Coercion->new(
380               type_coercion_map => [
381                 Num, qq{ int($i * int(\$_/$i)) }
382               ],
383             );
384           },
385         );
386
387       Now we can define an even number like this:
388
389         __PACKAGE__->add_type(
390           name     => 'EvenNumber',
391           parent   => __PACKAGE__->get_type('MultipleOf')->of(2),
392           coercion => 1,  # inherit from parent
393         );
394
395       Note that it is possible for a type constraint to have a "constraint"
396       and a "constraint_generator".
397
398         BaseType          # uses the constraint
399         BaseType[]        # constraint_generator with no arguments
400         BaseType[$x]      # constraint_generator with an argument
401
402       In the MultipleOf example above, MultipleOf[] with no number would
403       throw an error because of "assert_Int(shift)" not finding an integer.
404
405       But it is certainly possible for BaseType[] to be meaningful and
406       distinct from "BaseType".
407
408       For example, Tuple is just the same as ArrayRef and accepts any
409       arrayref as being valid. But Tuple[] will only accept arrayrefs with
410       zero elements in them. (Just like Tuple[Any,Any] will only accept
411       arrayrefs with two elements.)
412

NEXT STEPS

414       After that last example, probably have a little lie down. Once you're
415       recovered, here's your next step:
416
417       ยท   Type::Tiny::Manual::UsingWithMoose
418
419           How to use Type::Tiny with Moose, including the advantages of
420           Type::Tiny over built-in type constraints, and Moose-specific
421           features.
422

AUTHOR

424       Toby Inkster <tobyink@cpan.org>.
425
427       This software is copyright (c) 2013-2014, 2017-2020 by Toby Inkster.
428
429       This is free software; you can redistribute it and/or modify it under
430       the same terms as the Perl 5 programming language system itself.
431

DISCLAIMER OF WARRANTIES

433       THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
434       WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
435       MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
436
437
438
439perl v5.32.0                      2020-09-17  Type::Tiny::Manual::Libraries(3)
Impressum