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