Moved to MooseX-Types
[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;
52d358e2 14use MooseX::Types::Base ();
15use MooseX::Types::Util qw( filter_tags );
16use MooseX::Types::UndefinedType;
e211870f 17use Sub::Install qw( install_sub );
3df5416a 18use Moose;
8af0a70d 19use namespace::clean;
20
21our $VERSION = 0.01;
22
23my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'};
24
25=head1 SYNOPSIS
26
27 #
28 # Library Definition
29 #
30 package MyLibrary;
31 use strict;
32
33 # predeclare our own types
52d358e2 34 use MooseX::Types
8af0a70d 35 -declare => [qw( PositiveInt NegativeInt )];
36
37 # import builtin types
52d358e2 38 use MooseX::Types::Moose 'Int';
8af0a70d 39
40 # type definition
41 subtype PositiveInt,
42 as Int,
43 where { $_ > 0 },
44 message { "Int is not larger than 0" };
45
46 subtype NegativeInt,
47 as Int,
48 where { $_ < 0 },
49 message { "Int is not smaller than 0" };
50
51 # type coercion
52 coerce PositiveInt,
53 from Int,
54 via { 1 };
55
56 1;
57
58 #
59 # Usage
60 #
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
149=head1 LIBRARY USAGE
150
151You can import the L<"type helpers"|/"TYPE HANDLER FUNCTIONS"> of a
152library by C<use>ing it with a list of types to import as arguments. If
153you want all of them, use the C<:all> tag. For example:
154
155 use MyLibrary ':all';
156 use MyOtherLibrary qw( TypeA TypeB );
157
52d358e2 158MooseX::Types comes with a library of Moose' built-in types called
159L<MooseX::Types::Moose>.
8af0a70d 160
c20dc98b 161=head1 WRAPPING A LIBRARY
162
163You can define your own wrapper subclasses to manipulate the behaviour
164of a set of library exports. Here is an example:
165
166 package MyWrapper;
167 use strict;
168 use Class::C3;
52d358e2 169 use base 'MooseX::Types::Wrapper';
c20dc98b 170
171 sub coercion_export_generator {
172 my $class = shift;
173 my $code = $class->next::method(@_);
174 return sub {
175 my $value = $code->(@_);
176 warn "Coercion returned undef!"
177 unless defined $value;
178 return $value;
179 };
180 }
181
182 1;
183
184This class wraps the coercion generator (e.g., C<to_Int()>) and warns
185if a coercion returned an undefined value. You can wrap any library
186with this:
187
188 package Foo;
189 use strict;
190 use MyWrapper MyLibrary => [qw( Foo Bar )],
191 Moose => [qw( Str Int )];
192
193 ...
194 1;
195
196The C<Moose> library name is a special shortcut for
52d358e2 197L<MooseX::Types::Moose>.
c20dc98b 198
199=head2 Generator methods you can overload
200
201=over 4
202
203=item type_export_generator( $short, $full )
204
205Creates a closure returning the type's L<Moose::Meta::TypeConstraint>
206object.
207
208=item check_export_generator( $short, $full, $undef_message )
209
210This creates the closure used to test if a value is valid for this type.
211
212=item coercion_export_generator( $short, $full, $undef_message )
213
214This is the closure that's doing coercions.
215
216=back
217
218=head2 Provided Parameters
219
220=over 4
221
222=item $short
223
224The short, exported name of the type.
225
226=item $full
227
228The fully qualified name of this type as L<Moose> knows it.
229
230=item $undef_message
231
232A message that will be thrown when type functionality is used but the
233type does not yet exist.
234
235=back
236
8af0a70d 237=head1 METHODS
238
239=head2 import
240
52d358e2 241Installs the L<MooseX::Types::Base> class into the caller and
e211870f 242exports types according to the specification described in
243L</"LIBRARY DEFINITION">. This will continue to
244L<Moose::Util::TypeConstraints>' C<import> method to export helper
245functions you will need to declare your types.
246
8af0a70d 247=cut
248
249sub import {
250 my ($class, %args) = @_;
251 my $callee = caller;
252
253 # inject base class into new library
254 { no strict 'refs';
52d358e2 255 unshift @{ $callee . '::ISA' }, 'MooseX::Types::Base';
8af0a70d 256 }
257
258 # generate predeclared type helpers
e211870f 259 if (my @orig_declare = @{ $args{ -declare } || [] }) {
260 my ($tags, $declare) = filter_tags @orig_declare;
261
262 for my $type (@$declare) {
8af0a70d 263 $callee->add_type($type);
264 $callee->export_type_into(
265 $callee, $type,
266 sprintf($UndefMsg, $type, $callee),
267 -full => 1,
268 );
269 }
270 }
271
272 # run type constraints import
c20dc98b 273 return Moose::Util::TypeConstraints->import({ into => $callee });
8af0a70d 274}
275
276=head2 type_export_generator
277
e211870f 278Generate a type export, e.g. C<Int()>. This will return either a
279L<Moose::Meta::TypeConstraint> object, or alternatively a
52d358e2 280L<MooseX::Types::UndefinedType> object if the type was not
e211870f 281yet defined.
282
8af0a70d 283=cut
284
285sub type_export_generator {
286 my ($class, $type, $full) = @_;
e211870f 287 return sub {
288 return find_type_constraint($full)
52d358e2 289 || MooseX::Types::UndefinedType->new($full);
e211870f 290 };
8af0a70d 291}
292
293=head2 coercion_export_generator
294
e211870f 295This generates a coercion handler function, e.g. C<to_Int($value)>.
296
8af0a70d 297=cut
298
299sub coercion_export_generator {
300 my ($class, $type, $full, $undef_msg) = @_;
301 return sub {
302 my ($value) = @_;
303
304 # we need a type object
305 my $tobj = find_type_constraint($full) or croak $undef_msg;
306 my $return = $tobj->coerce($value);
307
308 # non-successful coercion returns false
309 return unless $tobj->check($return);
310
311 return $return;
312 }
313}
314
315=head2 check_export_generator
316
e211870f 317Generates a constraint check closure, e.g. C<is_Int($value)>.
318
8af0a70d 319=cut
320
321sub check_export_generator {
322 my ($class, $type, $full, $undef_msg) = @_;
323 return sub {
324 my ($value) = @_;
325
326 # we need a type object
327 my $tobj = find_type_constraint($full) or croak $undef_msg;
328
329 return $tobj->check($value);
330 }
331}
332
e211870f 333=head1 CAVEATS
334
335A library makes the types quasi-unique by prefixing their names with (by
336default) the library package name. If you're only using the type handler
52d358e2 337functions provided by MooseX::Types, you shouldn't ever have to use
e211870f 338a type's actual full name.
339
8af0a70d 340=head1 SEE ALSO
341
52d358e2 342L<Moose>, L<Moose::Util::TypeConstraints>, L<MooseX::Types::Moose>
8af0a70d 343
344=head1 AUTHOR AND COPYRIGHT
345
346Robert 'phaylon' Sedlacek C<E<lt>rs@474.atE<gt>>, with many thanks to
347the C<#moose> cabal on C<irc.perl.org>.
348
349=head1 LICENSE
350
351This program is free software; you can redistribute it and/or modify
352it under the same terms as perl itself.
353
354=cut
355
3561;