slightly better error handling
[gitmo/MooseX-Types.git] / lib / MooseX / Types.pm
CommitLineData
52d358e2 1package MooseX::Types;
16ddefbf 2use Moose;
8af0a70d 3
4=head1 NAME
5
52d358e2 6MooseX::Types - Organise your Moose types in libraries
8af0a70d 7
8=cut
9
3df5416a 10#use warnings;
11#use strict;
8af0a70d 12
8af0a70d 13use Moose::Util::TypeConstraints;
4c2125a4 14use MooseX::Types::TypeDecorator;
9616cebc 15use MooseX::Types::Base ();
16use MooseX::Types::Util qw( filter_tags );
52d358e2 17use MooseX::Types::UndefinedType;
16ddefbf 18use Carp::Clan qw( ^MooseX::Types );
9616cebc 19
20use namespace::clean -except => [qw( meta )];
8af0a70d 21
475bbd1d 22our $VERSION = 0.06;
8af0a70d 23
24my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'};
25
26=head1 SYNOPSIS
27
9616cebc 28=head2 Library Definition
29
8af0a70d 30 package MyLibrary;
8af0a70d 31
32 # predeclare our own types
52d358e2 33 use MooseX::Types
475bbd1d 34 -declare => [qw(
35 PositiveInt NegativeInt
36 ArrayRefOfPositiveInt ArrayRefOfAtLeastThreeNegativeInts
37 LotsOfInnerConstraints StrOrArrayRef
38 )];
8af0a70d 39
40 # import builtin types
52d358e2 41 use MooseX::Types::Moose 'Int';
8af0a70d 42
43 # type definition
44 subtype PositiveInt,
45 as Int,
46 where { $_ > 0 },
47 message { "Int is not larger than 0" };
48
49 subtype NegativeInt,
50 as Int,
51 where { $_ < 0 },
52 message { "Int is not smaller than 0" };
53
54 # type coercion
55 coerce PositiveInt,
56 from Int,
57 via { 1 };
58
d9002a85 59 # with parameterized constraints.
475bbd1d 60
61 subtype ArrayRefOfPositiveInt,
d9002a85 62 as ArrayRef[PositiveInt];
475bbd1d 63
64 subtype ArrayRefOfAtLeastThreeNegativeInts,
d9002a85 65 as ArrayRef[NegativeInt],
475bbd1d 66 where { scalar(@$_) > 2 };
67
68 subtype LotsOfInnerConstraints,
d9002a85 69 as ArrayRef[ArrayRef[HashRef[Int]]];
475bbd1d 70
71 # with TypeConstraint Unions
72
73 subtype StrOrArrayRef,
74 as Str|ArrayRef;
75
8af0a70d 76 1;
77
9616cebc 78=head2 Usage
79
8af0a70d 80 package Foo;
81 use Moose;
82 use MyLibrary qw( PositiveInt NegativeInt );
83
84 # use the exported constants as type names
85 has 'bar',
86 isa => PositiveInt,
87 is => 'rw';
88 has 'baz',
89 isa => NegativeInt,
90 is => 'rw';
91
92 sub quux {
93 my ($self, $value);
94
95 # test the value
96 print "positive\n" if is_PositiveInt($value);
97 print "negative\n" if is_NegativeInt($value);
98
99 # coerce the value, NegativeInt doesn't have a coercion
100 # helper, since it didn't define any coercions.
101 $value = to_PositiveInt($value) or die "Cannot coerce";
102 }
103
104 1;
105
106=head1 DESCRIPTION
107
108The types provided with L<Moose> are by design global. This package helps
109you to organise and selectively import your own and the built-in types in
110libraries. As a nice side effect, it catches typos at compile-time too.
111
112However, the main reason for this module is to provide an easy way to not
113have conflicts with your type names, since the internal fully qualified
114names of the types will be prefixed with the library's name.
115
116This module will also provide you with some helper functions to make it
117easier to use Moose types in your code.
118
119=head1 TYPE HANDLER FUNCTIONS
120
121=head2 $type
122
123A constant with the name of your type. It contains the type's fully
124qualified name. Takes no value, as all constants.
125
126=head2 is_$type
127
128This handler takes a value and tests if it is a valid value for this
129C<$type>. It will return true or false.
130
131=head2 to_$type
132
133A handler that will take a value and coerce it into the C<$type>. It will
134return a false value if the type could not be coerced.
135
136B<Important Note>: This handler will only be exported for types that can
137do type coercion. This has the advantage that a coercion to a type that
138cannot hasn't defined any coercions will lead to a compile-time error.
139
140=head1 LIBRARY DEFINITION
141
52d358e2 142A MooseX::Types is just a normal Perl module. Unlike Moose
8af0a70d 143itself, it does not install C<use strict> and C<use warnings> in your
144class by default, so this is up to you.
145
146The only thing a library is required to do is
147
52d358e2 148 use MooseX::Types -declare => \@types;
8af0a70d 149
150with C<@types> being a list of types you wish to define in this library.
151This line will install a proper base class in your package as well as the
152full set of L<handlers|/"TYPE HANDLER FUNCTIONS"> for your declared
153types. It will then hand control over to L<Moose::Util::TypeConstraints>'
154C<import> method to export the functions you will need to declare your
155types.
156
157If you want to use Moose' built-in types (e.g. for subtyping) you will
158want to
159
52d358e2 160 use MooseX::Types::Moose @types;
8af0a70d 161
52d358e2 162to import the helpers from the shipped L<MooseX::Types::Moose>
8af0a70d 163library which can export all types that come with Moose.
164
165You will have to define coercions for your types or your library won't
166export a L</to_$type> coercion helper for it.
167
21a1dfe2 168Note that you currently cannot define types containing C<::>, since
249888e7 169exporting would be a problem.
170
559cf3d8 171You also don't need to use C<warnings> and C<strict>, since the
172definition of a library automatically exports those.
173
8af0a70d 174=head1 LIBRARY USAGE
175
176You can import the L<"type helpers"|/"TYPE HANDLER FUNCTIONS"> of a
177library by C<use>ing it with a list of types to import as arguments. If
178you want all of them, use the C<:all> tag. For example:
179
180 use MyLibrary ':all';
181 use MyOtherLibrary qw( TypeA TypeB );
182
52d358e2 183MooseX::Types comes with a library of Moose' built-in types called
184L<MooseX::Types::Moose>.
8af0a70d 185
16ddefbf 186The exporting mechanism is, since version 0.5, implemented via a wrapper
187around L<Sub::Exporter>. This means you can do something like this:
188
189 use MyLibrary TypeA => { -as => 'MyTypeA' },
190 TypeB => { -as => 'MyTypeB' };
191
c20dc98b 192=head1 WRAPPING A LIBRARY
193
194You can define your own wrapper subclasses to manipulate the behaviour
195of a set of library exports. Here is an example:
196
197 package MyWrapper;
198 use strict;
199 use Class::C3;
52d358e2 200 use base 'MooseX::Types::Wrapper';
c20dc98b 201
202 sub coercion_export_generator {
203 my $class = shift;
204 my $code = $class->next::method(@_);
205 return sub {
206 my $value = $code->(@_);
207 warn "Coercion returned undef!"
208 unless defined $value;
209 return $value;
210 };
211 }
212
213 1;
214
215This class wraps the coercion generator (e.g., C<to_Int()>) and warns
216if a coercion returned an undefined value. You can wrap any library
217with this:
218
219 package Foo;
220 use strict;
221 use MyWrapper MyLibrary => [qw( Foo Bar )],
222 Moose => [qw( Str Int )];
223
224 ...
225 1;
226
227The C<Moose> library name is a special shortcut for
52d358e2 228L<MooseX::Types::Moose>.
c20dc98b 229
230=head2 Generator methods you can overload
231
232=over 4
233
234=item type_export_generator( $short, $full )
235
236Creates a closure returning the type's L<Moose::Meta::TypeConstraint>
237object.
238
239=item check_export_generator( $short, $full, $undef_message )
240
241This creates the closure used to test if a value is valid for this type.
242
243=item coercion_export_generator( $short, $full, $undef_message )
244
245This is the closure that's doing coercions.
246
247=back
248
249=head2 Provided Parameters
250
251=over 4
252
253=item $short
254
255The short, exported name of the type.
256
257=item $full
258
259The fully qualified name of this type as L<Moose> knows it.
260
261=item $undef_message
262
263A message that will be thrown when type functionality is used but the
264type does not yet exist.
265
475bbd1d 266=head1 NOTES REGARDING TYPE UNIONS
267
268L<MooseX::Types> uses L<MooseX::Types::TypeDecorator> to do some overloading
269which generally allows you to easily create union types:
270
271 subtype StrOrArrayRef,
272 as Str|ArrayRef;
273
274As with parameterized constrains, this overloading extends to modules using the
275types you define in a type library.
276
277 use Moose;
278 use MooseX::Types::Moose qw(HashRef Int);
279
280 has 'attr' => (isa=>HashRef|Int);
281
282And everything should just work as you'd think.
283
8af0a70d 284=head1 METHODS
285
286=head2 import
287
52d358e2 288Installs the L<MooseX::Types::Base> class into the caller and
e211870f 289exports types according to the specification described in
290L</"LIBRARY DEFINITION">. This will continue to
291L<Moose::Util::TypeConstraints>' C<import> method to export helper
292functions you will need to declare your types.
293
8af0a70d 294=cut
295
296sub import {
297 my ($class, %args) = @_;
298 my $callee = caller;
299
559cf3d8 300 # everyone should want this
301 strict->import;
302 warnings->import;
303
8af0a70d 304 # inject base class into new library
305 { no strict 'refs';
52d358e2 306 unshift @{ $callee . '::ISA' }, 'MooseX::Types::Base';
8af0a70d 307 }
308
309 # generate predeclared type helpers
e211870f 310 if (my @orig_declare = @{ $args{ -declare } || [] }) {
311 my ($tags, $declare) = filter_tags @orig_declare;
16ddefbf 312 my @to_export;
e211870f 313
314 for my $type (@$declare) {
249888e7 315
316 croak "Cannot create a type containing '::' ($type) at the moment"
317 if $type =~ /::/;
318
16ddefbf 319 # add type to library and remember to export
8af0a70d 320 $callee->add_type($type);
16ddefbf 321 push @to_export, $type;
8af0a70d 322 }
16ddefbf 323
324 $callee->import({ -full => 1, -into => $callee }, @to_export);
8af0a70d 325 }
326
327 # run type constraints import
c20dc98b 328 return Moose::Util::TypeConstraints->import({ into => $callee });
8af0a70d 329}
330
331=head2 type_export_generator
332
e211870f 333Generate a type export, e.g. C<Int()>. This will return either a
334L<Moose::Meta::TypeConstraint> object, or alternatively a
52d358e2 335L<MooseX::Types::UndefinedType> object if the type was not
e211870f 336yet defined.
337
8af0a70d 338=cut
339
340sub type_export_generator {
a706b0f2 341 my ($class, $type, $name) = @_;
686e5888 342
343 ## Return an anonymous subroutine that will generate the proxied type
344 ## constraint for you.
345
4c2125a4 346 return sub {
a706b0f2 347 my $type_constraint;
e088dd03 348 if(defined(my $params = shift @_)) {
686e5888 349 ## We currently only allow a TC to accept a single, ArrayRef
350 ## parameter, as in HashRef[Int], where [Int] is what's inside the
351 ## ArrayRef passed.
e088dd03 352 if(ref $params eq 'ARRAY') {
353 $type_constraint = $class->create_arged_type_constraint($name, @$params);
354 } else {
355 croak 'Arguments must be an ArrayRef, not '. ref $params;
356 }
a706b0f2 357 } else {
e088dd03 358 $type_constraint = $class->create_base_type_constraint($name);
359 }
360 $type_constraint = defined($type_constraint) ? $type_constraint
361 : MooseX::Types::UndefinedType->new($name);
475bbd1d 362
d9002a85 363 my $type_decorator = $class->create_type_decorator($type_constraint);
bb5b7b28 364
686e5888 365 ## If there are additional args, that means it's probably stuff that
366 ## needs to be returned to the subtype. Not an ideal solution here but
367 ## doesn't seem to cause trouble.
368
d9002a85 369 if(@_) {
370 return ($type_decorator, @_);
371 } else {
372 return $type_decorator;
373 }
e211870f 374 };
8af0a70d 375}
376
a706b0f2 377=head2 create_arged_type_constraint ($name, @args)
378
686e5888 379Given a String $name with @args find the matching typeconstraint and parameterize
380it with @args.
a706b0f2 381
382=cut
383
384sub create_arged_type_constraint {
385 my ($class, $name, @args) = @_;
575e6fc1 386 my $type_constraint = Moose::Util::TypeConstraints::find_or_create_type_constraint($name);
686e5888 387 return $type_constraint->parameterize(@args);
a706b0f2 388}
389
390=head2 create_base_type_constraint ($name)
391
392Given a String $name, find the matching typeconstraint.
393
394=cut
395
396sub create_base_type_constraint {
397 my ($class, $name) = @_;
398 return find_type_constraint($name);
399}
400
401=head2 create_type_decorator ($type_constraint)
402
403Given a $type_constraint, return a lightweight L<MooseX::Types::TypeDecorator>
404instance.
405
406=cut
407
408sub create_type_decorator {
409 my ($class, $type_constraint) = @_;
475bbd1d 410 return MooseX::Types::TypeDecorator->new($type_constraint);
a706b0f2 411}
412
8af0a70d 413=head2 coercion_export_generator
414
e211870f 415This generates a coercion handler function, e.g. C<to_Int($value)>.
416
8af0a70d 417=cut
418
419sub coercion_export_generator {
420 my ($class, $type, $full, $undef_msg) = @_;
421 return sub {
422 my ($value) = @_;
423
424 # we need a type object
425 my $tobj = find_type_constraint($full) or croak $undef_msg;
426 my $return = $tobj->coerce($value);
427
428 # non-successful coercion returns false
429 return unless $tobj->check($return);
430
431 return $return;
432 }
433}
434
435=head2 check_export_generator
436
e211870f 437Generates a constraint check closure, e.g. C<is_Int($value)>.
438
8af0a70d 439=cut
440
441sub check_export_generator {
442 my ($class, $type, $full, $undef_msg) = @_;
443 return sub {
444 my ($value) = @_;
445
446 # we need a type object
447 my $tobj = find_type_constraint($full) or croak $undef_msg;
448
449 return $tobj->check($value);
450 }
451}
452
e211870f 453=head1 CAVEATS
454
686e5888 455The following are lists of gotcha's and their workarounds for developers coming
456from the standard string based type constraint names
457
458=head2 Uniqueness
459
e211870f 460A library makes the types quasi-unique by prefixing their names with (by
461default) the library package name. If you're only using the type handler
52d358e2 462functions provided by MooseX::Types, you shouldn't ever have to use
e211870f 463a type's actual full name.
464
686e5888 465=head2 Argument separation ('=>' versus ',')
466
467The Perlop manpage has this to say about the '=>' operator: "The => operator is
468a synonym for the comma, but forces any word (consisting entirely of word
469characters) to its left to be interpreted as a string (as of 5.001). This
470includes words that might otherwise be considered a constant or function call."
471
472Due to this stringification, the following will NOT work as you might think:
473
474 subtype StrOrArrayRef => as Str|ArrayRef;
475
476The 'StrOrArrayRef' will have it's stringification activated this causes the
477subtype to not be created. Since the bareword type constraints are not strings
478you really should not try to treat them that way. You will have to use the ','
479operator instead. The author's of this package realize that all the L<Moose>
480documention and examples nearly uniformly use the '=>' version of the comma
481operator and this could be an issue if you are converting code.
482
483Patches welcome for discussion.
484
8af0a70d 485=head1 SEE ALSO
486
16ddefbf 487L<Moose>,
488L<Moose::Util::TypeConstraints>,
489L<MooseX::Types::Moose>,
490L<Sub::Exporter>
8af0a70d 491
492=head1 AUTHOR AND COPYRIGHT
493
494Robert 'phaylon' Sedlacek C<E<lt>rs@474.atE<gt>>, with many thanks to
495the C<#moose> cabal on C<irc.perl.org>.
496
475bbd1d 497Additional features by John Napiorkowski (jnapiorkowski) <jjnapiork@cpan.org>.
498
8af0a70d 499=head1 LICENSE
500
501This program is free software; you can redistribute it and/or modify
502it under the same terms as perl itself.
503
504=cut
505
5061;