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