overloading for union constraints, more tests, some code cleanup
[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
badcd0e5 22our $VERSION = 0.05;
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
8af0a70d 34 -declare => [qw( PositiveInt NegativeInt )];
35
36 # import builtin types
52d358e2 37 use MooseX::Types::Moose 'Int';
8af0a70d 38
39 # type definition
40 subtype PositiveInt,
41 as Int,
42 where { $_ > 0 },
43 message { "Int is not larger than 0" };
44
45 subtype NegativeInt,
46 as Int,
47 where { $_ < 0 },
48 message { "Int is not smaller than 0" };
49
50 # type coercion
51 coerce PositiveInt,
52 from Int,
53 via { 1 };
54
55 1;
56
9616cebc 57=head2 Usage
58
8af0a70d 59 package Foo;
60 use Moose;
61 use MyLibrary qw( PositiveInt NegativeInt );
62
63 # use the exported constants as type names
64 has 'bar',
65 isa => PositiveInt,
66 is => 'rw';
67 has 'baz',
68 isa => NegativeInt,
69 is => 'rw';
70
71 sub quux {
72 my ($self, $value);
73
74 # test the value
75 print "positive\n" if is_PositiveInt($value);
76 print "negative\n" if is_NegativeInt($value);
77
78 # coerce the value, NegativeInt doesn't have a coercion
79 # helper, since it didn't define any coercions.
80 $value = to_PositiveInt($value) or die "Cannot coerce";
81 }
82
83 1;
84
85=head1 DESCRIPTION
86
87The types provided with L<Moose> are by design global. This package helps
88you to organise and selectively import your own and the built-in types in
89libraries. As a nice side effect, it catches typos at compile-time too.
90
91However, the main reason for this module is to provide an easy way to not
92have conflicts with your type names, since the internal fully qualified
93names of the types will be prefixed with the library's name.
94
95This module will also provide you with some helper functions to make it
96easier to use Moose types in your code.
97
98=head1 TYPE HANDLER FUNCTIONS
99
100=head2 $type
101
102A constant with the name of your type. It contains the type's fully
103qualified name. Takes no value, as all constants.
104
105=head2 is_$type
106
107This handler takes a value and tests if it is a valid value for this
108C<$type>. It will return true or false.
109
110=head2 to_$type
111
112A handler that will take a value and coerce it into the C<$type>. It will
113return a false value if the type could not be coerced.
114
115B<Important Note>: This handler will only be exported for types that can
116do type coercion. This has the advantage that a coercion to a type that
117cannot hasn't defined any coercions will lead to a compile-time error.
118
119=head1 LIBRARY DEFINITION
120
52d358e2 121A MooseX::Types is just a normal Perl module. Unlike Moose
8af0a70d 122itself, it does not install C<use strict> and C<use warnings> in your
123class by default, so this is up to you.
124
125The only thing a library is required to do is
126
52d358e2 127 use MooseX::Types -declare => \@types;
8af0a70d 128
129with C<@types> being a list of types you wish to define in this library.
130This line will install a proper base class in your package as well as the
131full set of L<handlers|/"TYPE HANDLER FUNCTIONS"> for your declared
132types. It will then hand control over to L<Moose::Util::TypeConstraints>'
133C<import> method to export the functions you will need to declare your
134types.
135
136If you want to use Moose' built-in types (e.g. for subtyping) you will
137want to
138
52d358e2 139 use MooseX::Types::Moose @types;
8af0a70d 140
52d358e2 141to import the helpers from the shipped L<MooseX::Types::Moose>
8af0a70d 142library which can export all types that come with Moose.
143
144You will have to define coercions for your types or your library won't
145export a L</to_$type> coercion helper for it.
146
21a1dfe2 147Note that you currently cannot define types containing C<::>, since
249888e7 148exporting would be a problem.
149
559cf3d8 150You also don't need to use C<warnings> and C<strict>, since the
151definition of a library automatically exports those.
152
8af0a70d 153=head1 LIBRARY USAGE
154
155You can import the L<"type helpers"|/"TYPE HANDLER FUNCTIONS"> of a
156library by C<use>ing it with a list of types to import as arguments. If
157you want all of them, use the C<:all> tag. For example:
158
159 use MyLibrary ':all';
160 use MyOtherLibrary qw( TypeA TypeB );
161
52d358e2 162MooseX::Types comes with a library of Moose' built-in types called
163L<MooseX::Types::Moose>.
8af0a70d 164
16ddefbf 165The exporting mechanism is, since version 0.5, implemented via a wrapper
166around L<Sub::Exporter>. This means you can do something like this:
167
168 use MyLibrary TypeA => { -as => 'MyTypeA' },
169 TypeB => { -as => 'MyTypeB' };
170
c20dc98b 171=head1 WRAPPING A LIBRARY
172
173You can define your own wrapper subclasses to manipulate the behaviour
174of a set of library exports. Here is an example:
175
176 package MyWrapper;
177 use strict;
178 use Class::C3;
52d358e2 179 use base 'MooseX::Types::Wrapper';
c20dc98b 180
181 sub coercion_export_generator {
182 my $class = shift;
183 my $code = $class->next::method(@_);
184 return sub {
185 my $value = $code->(@_);
186 warn "Coercion returned undef!"
187 unless defined $value;
188 return $value;
189 };
190 }
191
192 1;
193
194This class wraps the coercion generator (e.g., C<to_Int()>) and warns
195if a coercion returned an undefined value. You can wrap any library
196with this:
197
198 package Foo;
199 use strict;
200 use MyWrapper MyLibrary => [qw( Foo Bar )],
201 Moose => [qw( Str Int )];
202
203 ...
204 1;
205
206The C<Moose> library name is a special shortcut for
52d358e2 207L<MooseX::Types::Moose>.
c20dc98b 208
209=head2 Generator methods you can overload
210
211=over 4
212
213=item type_export_generator( $short, $full )
214
215Creates a closure returning the type's L<Moose::Meta::TypeConstraint>
216object.
217
218=item check_export_generator( $short, $full, $undef_message )
219
220This creates the closure used to test if a value is valid for this type.
221
222=item coercion_export_generator( $short, $full, $undef_message )
223
224This is the closure that's doing coercions.
225
226=back
227
228=head2 Provided Parameters
229
230=over 4
231
232=item $short
233
234The short, exported name of the type.
235
236=item $full
237
238The fully qualified name of this type as L<Moose> knows it.
239
240=item $undef_message
241
242A message that will be thrown when type functionality is used but the
243type does not yet exist.
244
245=back
246
8af0a70d 247=head1 METHODS
248
249=head2 import
250
52d358e2 251Installs the L<MooseX::Types::Base> class into the caller and
e211870f 252exports types according to the specification described in
253L</"LIBRARY DEFINITION">. This will continue to
254L<Moose::Util::TypeConstraints>' C<import> method to export helper
255functions you will need to declare your types.
256
8af0a70d 257=cut
258
259sub import {
260 my ($class, %args) = @_;
261 my $callee = caller;
262
559cf3d8 263 # everyone should want this
264 strict->import;
265 warnings->import;
266
8af0a70d 267 # inject base class into new library
268 { no strict 'refs';
52d358e2 269 unshift @{ $callee . '::ISA' }, 'MooseX::Types::Base';
8af0a70d 270 }
271
272 # generate predeclared type helpers
e211870f 273 if (my @orig_declare = @{ $args{ -declare } || [] }) {
274 my ($tags, $declare) = filter_tags @orig_declare;
16ddefbf 275 my @to_export;
e211870f 276
277 for my $type (@$declare) {
249888e7 278
279 croak "Cannot create a type containing '::' ($type) at the moment"
280 if $type =~ /::/;
281
16ddefbf 282 # add type to library and remember to export
8af0a70d 283 $callee->add_type($type);
16ddefbf 284 push @to_export, $type;
8af0a70d 285 }
16ddefbf 286
287 $callee->import({ -full => 1, -into => $callee }, @to_export);
8af0a70d 288 }
289
290 # run type constraints import
c20dc98b 291 return Moose::Util::TypeConstraints->import({ into => $callee });
8af0a70d 292}
293
294=head2 type_export_generator
295
e211870f 296Generate a type export, e.g. C<Int()>. This will return either a
297L<Moose::Meta::TypeConstraint> object, or alternatively a
52d358e2 298L<MooseX::Types::UndefinedType> object if the type was not
e211870f 299yet defined.
300
8af0a70d 301=cut
302
303sub type_export_generator {
a706b0f2 304 my ($class, $type, $name) = @_;
4c2125a4 305 return sub {
a706b0f2 306 my $type_constraint;
307 if(my $params = shift @_) {
308 $type_constraint = $class->create_arged_type_constraint($name, @$params);
309 } else {
310 $type_constraint = $class->create_base_type_constraint($name)
311 || MooseX::Types::UndefinedType->new($name);
54f5d4e6 312 }
a706b0f2 313 return $class->create_type_decorator($type_constraint);
e211870f 314 };
8af0a70d 315}
316
a706b0f2 317=head2 create_arged_type_constraint ($name, @args)
318
319Given a String $name with @args find the matching typeconstraint.
320
321=cut
322
323sub create_arged_type_constraint {
324 my ($class, $name, @args) = @_;
325 ### This whole section is a real TODO :) Ugly hack to get the base tests working.
326 my $fullname = $name."[$args[0]]";
327 return Moose::Util::TypeConstraints::create_parameterized_type_constraint($fullname);
328}
329
330=head2 create_base_type_constraint ($name)
331
332Given a String $name, find the matching typeconstraint.
333
334=cut
335
336sub create_base_type_constraint {
337 my ($class, $name) = @_;
338 return find_type_constraint($name);
339}
340
341=head2 create_type_decorator ($type_constraint)
342
343Given a $type_constraint, return a lightweight L<MooseX::Types::TypeDecorator>
344instance.
345
346=cut
347
348sub create_type_decorator {
349 my ($class, $type_constraint) = @_;
350 return MooseX::Types::TypeDecorator->new(type_constraint=>$type_constraint);
351}
352
8af0a70d 353=head2 coercion_export_generator
354
e211870f 355This generates a coercion handler function, e.g. C<to_Int($value)>.
356
8af0a70d 357=cut
358
359sub coercion_export_generator {
360 my ($class, $type, $full, $undef_msg) = @_;
361 return sub {
362 my ($value) = @_;
363
364 # we need a type object
365 my $tobj = find_type_constraint($full) or croak $undef_msg;
366 my $return = $tobj->coerce($value);
367
368 # non-successful coercion returns false
369 return unless $tobj->check($return);
370
371 return $return;
372 }
373}
374
375=head2 check_export_generator
376
e211870f 377Generates a constraint check closure, e.g. C<is_Int($value)>.
378
8af0a70d 379=cut
380
381sub check_export_generator {
382 my ($class, $type, $full, $undef_msg) = @_;
383 return sub {
384 my ($value) = @_;
385
386 # we need a type object
387 my $tobj = find_type_constraint($full) or croak $undef_msg;
388
389 return $tobj->check($value);
390 }
391}
392
e211870f 393=head1 CAVEATS
394
395A library makes the types quasi-unique by prefixing their names with (by
396default) the library package name. If you're only using the type handler
52d358e2 397functions provided by MooseX::Types, you shouldn't ever have to use
e211870f 398a type's actual full name.
399
8af0a70d 400=head1 SEE ALSO
401
16ddefbf 402L<Moose>,
403L<Moose::Util::TypeConstraints>,
404L<MooseX::Types::Moose>,
405L<Sub::Exporter>
8af0a70d 406
407=head1 AUTHOR AND COPYRIGHT
408
409Robert 'phaylon' Sedlacek C<E<lt>rs@474.atE<gt>>, with many thanks to
410the C<#moose> cabal on C<irc.perl.org>.
411
412=head1 LICENSE
413
414This program is free software; you can redistribute it and/or modify
415it under the same terms as perl itself.
416
417=cut
418
4191;