1Type::Tiny::Manual::LibUrsaerrieCso(n3t)ributed Perl DocTuympeen:t:aTtiinoyn::Manual::Libraries(3)
2
3
4
6 Type::Tiny::Manual::Libraries - how to build a type library with
7 Type::Tiny, Type::Library and Type::Utils
8
10 A type library is a collection of type constraints, optionally with
11 coercions.
12
13 The following is an example type library:
14
15 package Example::Types;
16
17 use Type::Library
18 -base,
19 -declare => qw( Datetime DatetimeHash EpochHash );
20 use Type::Utils -all;
21 use Types::Standard -types;
22
23 class_type Datetime, { class => "DateTime" };
24
25 declare DatetimeHash,
26 as Dict[
27 year => Int,
28 month => Optional[ Int ],
29 day => Optional[ Int ],
30 hour => Optional[ Int ],
31 minute => Optional[ Int ],
32 second => Optional[ Int ],
33 nanosecond => Optional[ Int ],
34 time_zone => Optional[ Str ],
35 ];
36
37 declare EpochHash,
38 as Dict[ epoch => Int ];
39
40 coerce Datetime,
41 from Int, via { "DateTime"->from_epoch(epoch => $_) },
42 from Undef, via { "DateTime"->now },
43 from DatetimeHash, via { "DateTime"->new(%$_) },
44 from EpochHash, via { "DateTime"->from_epoch(%$_) };
45
46 1;
47
49 Here's a line by line description of what's going on in the type
50 library.
51
52 package Example::Types;
53
54 Type libraries are packages. It is recommended that re-usable type
55 libraries be given a name in the "Types::*" namespace. For application-
56 specific type libraries, assuming your application's namespace is
57 "MyApp::*" then name the type library "MyApp::Types", or if more than
58 one is needed, use the "MyApp::Types::*" namespace.
59
60 use Type::Library
61 -base,
62 -declare => qw( Datetime DatetimeHash EpochHash );
63
64 The "-base" part is used to establish inheritance. It makes
65 "Example::Types" a child class of "Type::Library".
66
67 Declaring the types we're going to define ahead of their definition
68 allows us to use them as barewords later on. (Note that in code which
69 uses our type library, the types will always be available as barewords.
70 The declaration above just allows us to use them within the library
71 itself.)
72
73 use Type::Utils -all;
74
75 Imports some utility functions from Type::Utils. These will be useful
76 for defining our types and the relationships between them.
77
78 use Types::Standard -types;
79
80 Here we import a standard set of type constraints from Types::Standard.
81 There is no need to do this, but it's often helpful to have a base set
82 of types which we can define our own in terms of.
83
84 Note that although we've imported the types to be able to use in our
85 library, we haven't added the types to our library. We've imported
86 "Str", but other people won't be able to re-import "Str" from our
87 library. If you actually want your library to extend another library,
88 do this instead:
89
90 BEGIN { extends "Types::AnotherLibrary" };
91
92 (Note: if your code breaks here when you upgrade from version 0.006 or
93 below, saying that the 'extends' keyword has not been declared, just
94 add '-all' after use Type::Utils.)
95
96 OK, now we're ready to declare a few types.
97
98 class_type Datetime, { class => "DateTime" };
99
100 This creates a type constraint named "Datetime" which is all objects
101 blessed into the DateTime package. Because this type constraint is not
102 anonymous (it has a name), it will be automagically installed into the
103 type library.
104
105 The next two statements declare two further types constraints, using
106 type constraints from the Types::Standard library. Let's look at
107 "EpochHash" in more detail. This is a hashref with one key called
108 "epoch" and a value which is an integer.
109
110 declare EpochHash,
111 as Dict[ epoch => Int ];
112
113 "EpochHash" inherits from the "Dict" type defined in Types::Standard.
114 It equally could have been defined as:
115
116 declare EpochHash,
117 as HashRef[Int],
118 where { scalar(keys(%$_))==1 and exists $_->{epoch} };
119
120 Or even:
121
122 declare EpochHash,
123 where {
124 ref($_) eq "HASH"
125 and scalar(keys(%$_))==1
126 and exists $_->{epoch}
127 };
128
129 Lastly we set up coercions. It's best to define all your types before
130 you define any coercions.
131
132 coerce Datetime,
133 from Int, via { "DateTime"->from_epoch(epoch => $_) },
134 from Undef, via { "DateTime"->now },
135 from DatetimeHash, via { "DateTime"->new(%$_) },
136 from EpochHash, via { "DateTime"->from_epoch(%$_) };
137
138 These are simply coderefs that will be fired when you want a Datetime,
139 but are given something else. For more information on coercions, see
140 Type::Tiny::Manual::Coercions.
141
142 Using Your Library
143 Use a custom types library just like you would Types::Standard:
144
145 package MyClass;
146 use Moose;
147 use DateTime;
148 use Example::Types qw( Datetime ); # import the custom type
149
150 has 'sometime' => (
151 is => 'rw',
152 isa => Datetime,
153 coerce => 1,
154 );
155
156 Type libraries defined with Type::Library are also able to export some
157 convenience functions:
158
159 use Example::Types qw( is_Datetime to_Datetime assert_Datetime );
160
161 my $dt = Foo::get_datetime;
162
163 unless ( is_Datetime $dt )
164 {
165 $dt = to_Datetime $dt;
166 }
167
168 assert_Datetime $dt;
169
170 These functions act as shortcuts for:
171
172 use Example::Types qw( Datetime );
173
174 my $dt = Foo::get_datetime;
175
176 unless ( Datetime->check($dt) )
177 {
178 $dt = Datetime->coerce($dt);
179 }
180
181 Datetime->assert_return($dt);
182
183 Pick whichever style you think is clearer!
184
185 Type::Library-based libraries provide a shortcut for importing a type
186 constraint along with all its associated convenience functions:
187
188 # Shortcut for qw( DateTime is_Datetime to_Datetime assert_Datetime )
189 #
190 use Example::Types qw( +Datetime );
191
192 See Type::Tiny::Manual for other ways to make use of type libraries.
193
195 Messages
196 It is sometimes nice to be able to emit a more useful error message
197 than the standard:
198
199 Value "Foo" did not pass type constraint "Bar"
200
201 It is possible to define custom error messages for types.
202
203 declare MediumInteger, as Integer,
204 where { $_ >= 10 and $_ < 20 },
205 message {
206 return Integer->get_message($_) if !Integer->check($_);
207 return "$_ is too small!" if $_ < 10;
208 return "$_ is so very, very big!";
209 };
210
211 Parameterized Constraints
212 Parameterized type constraints are those that can generate simple child
213 type constraints by passing parameters to their "parameterize" method.
214 For example, ArrayRef in Types::Standard:
215
216 use Types::Standard;
217
218 my $ArrayRef = Types::Standard::ArrayRef;
219 my $Int = Types::Standard::Int;
220 my $ArrayRef_of_Ints = $ArrayRef->parameterize($Int);
221
222 Type libraries provide some convenient sugar for this:
223
224 use Types::Standard qw( ArrayRef Int );
225
226 my $ArrayRef_of_Ints = ArrayRef[Int];
227
228 Unlike Moose which has separate meta classes for parameterizable,
229 parameterized and non-parameterizable type constraints, Type::Tiny
230 handles all that in one.
231
232 To create a parameterizable type constraint, you'll need to pass an
233 extra named parameter to "declare". Let's imagine that we want to make
234 our earlier "NonEmptyHash" constraint accept a parameter telling it the
235 minimum size of the hash. For example "NonEmptyHash[4]" would need to
236 contain at least four key-value pairs. Here's how you'd do it:
237
238 declare NonEmptyHash, as HashLike,
239 where { scalar values %$_ },
240 inline_as {
241 my ($constraint, $varname) = @_;
242 return sprintf(
243 '%s and scalar values %%{%s}',
244 $constraint->parent->inline_check($varname),
245 $varname,
246 );
247 },
248 # Generate a new "where" coderef...
249 constraint_generator => sub {
250 my ($minimum) = @_;
251 die "parameter must be positive" unless int($minimum) > 0;
252 return sub {
253 scalar(values(%$_)) >= int($minimum);
254 };
255 },
256 # Generate a new "inline_as" coderef...
257 inline_generator => sub {
258 my ($minimum) = @_;
259 return sub {
260 my ($constraint, $varname) = @_;
261 return sprintf(
262 '%s and scalar(values(%%{%s})) >= %d',
263 $constraint->parent->inline_check($varname),
264 $varname,
265 $minimum,
266 );
267 };
268 };
269
271 Some type libraries on CPAN:
272
273 · Types::Standard
274
275 · Types::Path::Tiny
276
277 · Types::XSD / Types::XSD::Lite
278
279 · Types::Set
280
281 · more <https://github.com/tobyink/p5-type-tiny/wiki/Type-libraries>!
282
284 Toby Inkster <tobyink@cpan.org>.
285
287 This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster.
288
289 This is free software; you can redistribute it and/or modify it under
290 the same terms as the Perl 5 programming language system itself.
291
293 THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
294 WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
295 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
296
297
298
299perl v5.28.1 2019-01-08 Type::Tiny::Manual::Libraries(3)