added has_available_type_export introspection utility function
[gitmo/MooseX-Types.git] / lib / MooseX / Types / Base.pm
CommitLineData
52d358e2 1package MooseX::Types::Base;
16ddefbf 2use Moose;
e211870f 3
4=head1 NAME
5
52d358e2 6MooseX::Types::Base - Type library base class
e211870f 7
8=cut
9
16ddefbf 10#use Data::Dump qw( dump );
9563f55e 11use Carp::Clan qw( ^MooseX::Types );
9616cebc 12use MooseX::Types::Util qw( filter_tags );
16ddefbf 13use Sub::Exporter qw( build_exporter );
8af0a70d 14use Moose::Util::TypeConstraints;
9616cebc 15
16use namespace::clean -except => [qw( meta )];
8af0a70d 17
e211870f 18=head1 DESCRIPTION
19
20You normally won't need to interact with this class by yourself. It is
21merely a collection of functionality that type libraries need to
52d358e2 22interact with moose and the rest of the L<MooseX::Types> module.
e211870f 23
24=cut
25
8af0a70d 26my $UndefMsg = q{Unable to find type '%s' in library '%s'};
27
e211870f 28=head1 METHODS
29
30=cut
31
32=head2 import
33
34Provides the import mechanism for your library. See
52d358e2 35L<MooseX::Types/"LIBRARY USAGE"> for syntax details on this.
e211870f 36
37=cut
38
8af0a70d 39sub import {
c20dc98b 40 my ($class, @args) = @_;
e211870f 41
16ddefbf 42 # filter or create options hash for S:E
43 my $options = (@args and (ref($args[0]) eq 'HASH')) ? $args[0] : undef;
44 unless ($options) {
45 $options = {foo => 23};
46 unshift @args, $options;
47 }
8af0a70d 48
16ddefbf 49 # all types known to us
50 my @types = $class->type_names;
8af0a70d 51
16ddefbf 52 # determine the wrapper, -into is supported for compatibility reasons
53 my $wrapper = $options->{ -wrapper } || 'MooseX::Types';
54 $args[0]->{into} = $options->{ -into }
55 if exists $options->{ -into };
56
57 my (%ex_spec, %ex_util);
8af0a70d 58 TYPE:
16ddefbf 59 for my $type_short (@types) {
60
61 # find type name and object, create undefined message
62 my $type_full = $class->get_type($type_short)
63 or croak "No fully qualified type name stored for '$type_short'";
64 my $type_cons = find_type_constraint($type_full);
65 my $undef_msg = sprintf($UndefMsg, $type_short, $class);
66
67 # the type itself
68 push @{ $ex_spec{exports} },
69 $type_short,
5885c4f4 70 sub {
71 bless $wrapper->type_export_generator($type_short, $type_full),
72 'MooseX::Types::EXPORTED_TYPE_CONSTRAINT';
73 };
16ddefbf 74
75 # the check helper
76 push @{ $ex_spec{exports} },
77 "is_${type_short}",
78 sub { $wrapper->check_export_generator($type_short, $type_full, $undef_msg) };
79
80 # only export coercion helper if full (for libraries) or coercion is defined
81 next TYPE
82 unless $options->{ -full }
83 or ($type_cons and $type_cons->has_coercion);
84 push @{ $ex_spec{exports} },
85 "to_${type_short}",
86 sub { $wrapper->coercion_export_generator($type_short, $type_full, $undef_msg) };
87 $ex_util{ $type_short }{to}++; # shortcut to remember this exists
8af0a70d 88 }
e211870f 89
16ddefbf 90 # create S:E exporter and increase export level unless specified explicitly
91 my $exporter = build_exporter \%ex_spec;
92 $options->{into_level}++
93 unless $options->{into};
e211870f 94
16ddefbf 95 # remember requested symbols to determine what helpers to auto-export
96 my %was_requested =
97 map { ($_ => 1) }
98 grep { not ref }
99 @args;
e211870f 100
16ddefbf 101 # determine which additional symbols (helpers) to export along
102 my %add;
103 EXPORT:
104 for my $type (grep { exists $was_requested{ $_ } } @types) {
105 $add{ "is_$type" }++
106 unless $was_requested{ "is_$type" };
107 next EXPORT
108 unless exists $ex_util{ $type }{to};
109 $add{ "to_$type" }++
110 unless $was_requested{ "to_$type" };
e211870f 111 }
8af0a70d 112
16ddefbf 113 # and on to the real exporter
114 my @new_args = (@args, keys %add);
115 return $class->$exporter(@new_args);
8af0a70d 116}
117
e211870f 118=head2 get_type
119
120This returns a type from the library's store by its name.
121
122=cut
123
8af0a70d 124sub get_type {
125 my ($class, $type) = @_;
126
127 # useful message if the type couldn't be found
128 croak "Unknown type '$type' in library '$class'"
129 unless $class->has_type($type);
130
131 # return real name of the type
132 return $class->type_storage->{ $type };
133}
134
e211870f 135=head2 type_names
136
137Returns a list of all known types by their name.
138
139=cut
140
8af0a70d 141sub type_names {
142 my ($class) = @_;
143
144 # return short names of all stored types
145 return keys %{ $class->type_storage };
146}
147
e211870f 148=head2 add_type
149
150Adds a new type to the library.
151
152=cut
153
8af0a70d 154sub add_type {
155 my ($class, $type) = @_;
156
157 # store type with library prefix as real name
158 $class->type_storage->{ $type } = "${class}::${type}";
159}
160
e211870f 161=head2 has_type
162
163Returns true or false depending on if this library knows a type by that
164name.
165
166=cut
167
8af0a70d 168sub has_type {
169 my ($class, $type) = @_;
170
171 # check if we stored a type under that name
172 return ! ! $class->type_storage->{ $type };
173}
174
e211870f 175=head2 type_storage
176
177Returns the library's type storage hash reference. You shouldn't use this
178method directly unless you know what you are doing. It is not an internal
179method because overriding it makes virtual libraries very easy.
180
181=cut
182
8af0a70d 183sub type_storage {
184 my ($class) = @_;
185
186 # return a reference to the storage in ourself
187 { no strict 'refs';
188 return \%{ $class . '::__MOOSEX_TYPELIBRARY_STORAGE' };
189 }
190}
191
e211870f 192=head1 SEE ALSO
193
52d358e2 194L<MooseX::Types::Moose>
e211870f 195
196=head1 AUTHOR AND COPYRIGHT
197
198Robert 'phaylon' Sedlacek C<E<lt>rs@474.atE<gt>>, with many thanks to
199the C<#moose> cabal on C<irc.perl.org>.
200
201=head1 LICENSE
202
203This program is free software; you can redistribute it and/or modify
204it under the same terms as perl itself.
205
206=cut
207
8af0a70d 2081;