1Type::Tiny::Manual::LibUrsaerrieCso(n3t)ributed Perl DocTuympeen:t:aTtiinoyn::Manual::Libraries(3)
2
3
4
6 Type::Tiny::Manual::Libraries - defining your own type libraries
7
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
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
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
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)