use correct export mechanism
[gitmo/MooseX-Types.git] / lib / MooseX / TypeLibrary.pm
CommitLineData
8af0a70d 1package MooseX::TypeLibrary;
2
3=head1 NAME
4
5MooseX::TypeLibrary - Organise your Moose types in libraries
6
7=cut
8
9use warnings;
10use strict;
11
12use Sub::Uplevel;
13use Moose::Util::TypeConstraints;
14use MooseX::TypeLibrary::Base;
e211870f 15use MooseX::TypeLibrary::Util qw( filter_tags );
16use MooseX::TypeLibrary::UndefinedType;
17use Sub::Install qw( install_sub );
8af0a70d 18use namespace::clean;
19
20our $VERSION = 0.01;
21
22my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'};
23
24=head1 SYNOPSIS
25
26 #
27 # Library Definition
28 #
29 package MyLibrary;
30 use strict;
31
32 # predeclare our own types
33 use MooseX::TypeLibrary
34 -declare => [qw( PositiveInt NegativeInt )];
35
36 # import builtin types
37 use MooseX::TypeLibrary::Moose 'Int';
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
57 #
58 # Usage
59 #
60 package Foo;
61 use Moose;
62 use MyLibrary qw( PositiveInt NegativeInt );
63
64 # use the exported constants as type names
65 has 'bar',
66 isa => PositiveInt,
67 is => 'rw';
68 has 'baz',
69 isa => NegativeInt,
70 is => 'rw';
71
72 sub quux {
73 my ($self, $value);
74
75 # test the value
76 print "positive\n" if is_PositiveInt($value);
77 print "negative\n" if is_NegativeInt($value);
78
79 # coerce the value, NegativeInt doesn't have a coercion
80 # helper, since it didn't define any coercions.
81 $value = to_PositiveInt($value) or die "Cannot coerce";
82 }
83
84 1;
85
86=head1 DESCRIPTION
87
88The types provided with L<Moose> are by design global. This package helps
89you to organise and selectively import your own and the built-in types in
90libraries. As a nice side effect, it catches typos at compile-time too.
91
92However, the main reason for this module is to provide an easy way to not
93have conflicts with your type names, since the internal fully qualified
94names of the types will be prefixed with the library's name.
95
96This module will also provide you with some helper functions to make it
97easier to use Moose types in your code.
98
99=head1 TYPE HANDLER FUNCTIONS
100
101=head2 $type
102
103A constant with the name of your type. It contains the type's fully
104qualified name. Takes no value, as all constants.
105
106=head2 is_$type
107
108This handler takes a value and tests if it is a valid value for this
109C<$type>. It will return true or false.
110
111=head2 to_$type
112
113A handler that will take a value and coerce it into the C<$type>. It will
114return a false value if the type could not be coerced.
115
116B<Important Note>: This handler will only be exported for types that can
117do type coercion. This has the advantage that a coercion to a type that
118cannot hasn't defined any coercions will lead to a compile-time error.
119
120=head1 LIBRARY DEFINITION
121
122A MooseX::TypeLibrary is just a normal Perl module. Unlike Moose
123itself, it does not install C<use strict> and C<use warnings> in your
124class by default, so this is up to you.
125
126The only thing a library is required to do is
127
128 use MooseX::TypeLibrary -declare => \@types;
129
130with C<@types> being a list of types you wish to define in this library.
131This line will install a proper base class in your package as well as the
132full set of L<handlers|/"TYPE HANDLER FUNCTIONS"> for your declared
133types. It will then hand control over to L<Moose::Util::TypeConstraints>'
134C<import> method to export the functions you will need to declare your
135types.
136
137If you want to use Moose' built-in types (e.g. for subtyping) you will
138want to
139
140 use MooseX::TypeLibrary::Moose @types;
141
142to import the helpers from the shipped L<MooseX::TypeLibrary::Moose>
143library which can export all types that come with Moose.
144
145You will have to define coercions for your types or your library won't
146export a L</to_$type> coercion helper for it.
147
148=head1 LIBRARY USAGE
149
150You can import the L<"type helpers"|/"TYPE HANDLER FUNCTIONS"> of a
151library by C<use>ing it with a list of types to import as arguments. If
152you want all of them, use the C<:all> tag. For example:
153
154 use MyLibrary ':all';
155 use MyOtherLibrary qw( TypeA TypeB );
156
157MooseX::TypeLibrary comes with a library of Moose' built-in types called
158L<MooseX::TypeLibrary::Moose>.
159
160=head1 METHODS
161
162=head2 import
163
e211870f 164Installs the L<MooseX::TypeLibrary::Base> class into the caller and
165exports types according to the specification described in
166L</"LIBRARY DEFINITION">. This will continue to
167L<Moose::Util::TypeConstraints>' C<import> method to export helper
168functions you will need to declare your types.
169
8af0a70d 170=cut
171
172sub import {
173 my ($class, %args) = @_;
174 my $callee = caller;
175
176 # inject base class into new library
177 { no strict 'refs';
178 unshift @{ $callee . '::ISA' }, 'MooseX::TypeLibrary::Base';
179 }
180
181 # generate predeclared type helpers
e211870f 182 if (my @orig_declare = @{ $args{ -declare } || [] }) {
183 my ($tags, $declare) = filter_tags @orig_declare;
184
185 for my $type (@$declare) {
8af0a70d 186 $callee->add_type($type);
187 $callee->export_type_into(
188 $callee, $type,
189 sprintf($UndefMsg, $type, $callee),
190 -full => 1,
191 );
192 }
193 }
194
195 # run type constraints import
de3e7243 196 return Moose::Util::TypeConstraints
197 ->import({ into => $callee });
198# return uplevel 1,
199# Moose::Util::TypeConstraints->can('import'),
200# 'Moose::Util::TypeConstraints';
8af0a70d 201}
202
203=head2 type_export_generator
204
e211870f 205Generate a type export, e.g. C<Int()>. This will return either a
206L<Moose::Meta::TypeConstraint> object, or alternatively a
207L<MooseX::TypeLibrary::UndefinedType> object if the type was not
208yet defined.
209
8af0a70d 210=cut
211
212sub type_export_generator {
213 my ($class, $type, $full) = @_;
e211870f 214 return sub {
215 return find_type_constraint($full)
216 || MooseX::TypeLibrary::UndefinedType->new($full);
217 };
8af0a70d 218}
219
220=head2 coercion_export_generator
221
e211870f 222This generates a coercion handler function, e.g. C<to_Int($value)>.
223
8af0a70d 224=cut
225
226sub coercion_export_generator {
227 my ($class, $type, $full, $undef_msg) = @_;
228 return sub {
229 my ($value) = @_;
230
231 # we need a type object
232 my $tobj = find_type_constraint($full) or croak $undef_msg;
233 my $return = $tobj->coerce($value);
234
235 # non-successful coercion returns false
236 return unless $tobj->check($return);
237
238 return $return;
239 }
240}
241
242=head2 check_export_generator
243
e211870f 244Generates a constraint check closure, e.g. C<is_Int($value)>.
245
8af0a70d 246=cut
247
248sub check_export_generator {
249 my ($class, $type, $full, $undef_msg) = @_;
250 return sub {
251 my ($value) = @_;
252
253 # we need a type object
254 my $tobj = find_type_constraint($full) or croak $undef_msg;
255
256 return $tobj->check($value);
257 }
258}
259
e211870f 260=head1 CAVEATS
261
262A library makes the types quasi-unique by prefixing their names with (by
263default) the library package name. If you're only using the type handler
264functions provided by MooseX::TypeLibrary, you shouldn't ever have to use
265a type's actual full name.
266
8af0a70d 267=head1 SEE ALSO
268
269L<Moose>, L<Moose::Util::TypeConstraints>, L<MooseX::TypeLibrary::Moose>
270
271=head1 AUTHOR AND COPYRIGHT
272
273Robert 'phaylon' Sedlacek C<E<lt>rs@474.atE<gt>>, with many thanks to
274the C<#moose> cabal on C<irc.perl.org>.
275
276=head1 LICENSE
277
278This program is free software; you can redistribute it and/or modify
279it under the same terms as perl itself.
280
281=cut
282
2831;