Fix several issue on Mouse::Exporter
[gitmo/Mouse.git] / lib / Mouse / Exporter.pm
CommitLineData
db9fc237 1package Mouse::Exporter;
2use strict;
3use warnings;
4
5use Carp qw(confess);
6
db9fc237 7my %SPEC;
8
1ff34b4c 9my $strict_bits = strict::bits(qw(subs refs vars));
10
0eb86915 11# it must be "require", because Mouse::Util depends on Mouse::Exporter,
12# which depends on Mouse::Util::import()
13require Mouse::Util;
14
1bd3c83e 15sub import{
16 $^H |= $strict_bits; # strict->import;
17 ${^WARNING_BITS} = $warnings::Bits{all}; # warnings->import;
18 return;
19}
20
0eb86915 21
db9fc237 22sub setup_import_methods{
23 my($class, %args) = @_;
24
25 my $exporting_package = $args{exporting_package} ||= caller();
26
27 $SPEC{$exporting_package} = \%args;
28
29 # canonicalize args
30 my @export_from;
31 if($args{also}){
32 my %seen;
33 my @stack = ($exporting_package);
34
35 while(my $current = shift @stack){
36 push @export_from, $current;
37
38 my $also = $SPEC{$current}{also} or next;
0eb86915 39 push @stack, grep{ !$seen{$_}++ } ref($also) ? @{ $also } : $also;
db9fc237 40 }
41 }
42 else{
43 @export_from = ($exporting_package);
44 }
45
46 {
47 my %exports;
48 my @removables;
4ee3190e 49 my @all;
db9fc237 50
1ff34b4c 51 my @init_meta_methods;
52
db9fc237 53 foreach my $package(@export_from){
54 my $spec = $SPEC{$package} or next;
55
56 if(my $as_is = $spec->{as_is}){
57 foreach my $thingy (@{$as_is}){
4ee3190e 58 my($code_package, $code_name, $code);
db9fc237 59
60 if(ref($thingy)){
db9fc237 61 $code = $thingy;
1bd3c83e 62 ($code_package, $code_name) = Mouse::Util::get_code_info($code);
db9fc237 63 }
64 else{
65 no strict 'refs';
4ee3190e 66 $code_package = $package;
67 $code_name = $thingy;
68 $code = \&{ $code_package . '::' . $code_name };
db9fc237 69 }
70
4ee3190e 71 push @all, $code_name;
72 $exports{$code_name} = $code;
73 if($code_package eq $package){
74 push @removables, $code_name;
75 }
db9fc237 76 }
77 }
1ff34b4c 78
79 if(my $init_meta = $package->can('init_meta')){
80 if(!grep{ $_ == $init_meta } @init_meta_methods){
81 unshift @init_meta_methods, $init_meta;
82 }
83 }
db9fc237 84 }
85 $args{EXPORTS} = \%exports;
86 $args{REMOVABLES} = \@removables;
87
1bd3c83e 88 $args{groups}{all} ||= \@all;
1ff34b4c 89
1bd3c83e 90 if(my $default_list = $args{groups}{default}){
1ff34b4c 91 my %default;
92 foreach my $keyword(@{$default_list}){
93 $default{$keyword} = $exports{$keyword}
94 || confess(qq{The $exporting_package package does not export "$keyword"});
95 }
96 $args{DEFAULT} = \%default;
97 }
98 else{
1bd3c83e 99 $args{groups}{default} ||= \@all;
100 $args{DEFAULT} = $args{EXPORTS};
1ff34b4c 101 }
102
103 if(@init_meta_methods){
104 $args{INIT_META} = \@init_meta_methods;
105 }
db9fc237 106 }
107
108 no strict 'refs';
109
110 *{$exporting_package . '::import'} = \&do_import;
111 *{$exporting_package . '::unimport'} = \&do_unimport;
112
db9fc237 113 return;
114}
115
db9fc237 116
117# the entity of general import()
118sub do_import {
1ff34b4c 119 my($package, @args) = @_;
db9fc237 120
1ff34b4c 121 my $spec = $SPEC{$package}
122 || confess("The package $package package does not use Mouse::Exporter");
db9fc237 123
124 my $into = _get_caller_package(ref($args[0]) ? shift @args : undef);
125
126 my @exports;
127 foreach my $arg(@args){
1ff34b4c 128 if($arg =~ s/^-//){
1bd3c83e 129 Mouse::Util::not_supported("-$arg");
1ff34b4c 130 }
131 elsif($arg =~ s/^://){
1bd3c83e 132 my $group = $spec->{groups}{$arg}
1ff34b4c 133 || confess(qq{The $package package does not export the group "$arg"});
db9fc237 134 push @exports, @{$group};
135 }
136 else{
137 push @exports, $arg;
138 }
139 }
140
1ff34b4c 141 $^H |= $strict_bits; # strict->import;
142 ${^WARNING_BITS} = $warnings::Bits{all}; # warnings->import;
db9fc237 143
0eb86915 144 if($into eq 'main' && !$spec->{_export_to_main}){
1ff34b4c 145 warn qq{$package does not export its sugar to the 'main' package.\n};
db9fc237 146 return;
147 }
148
1ff34b4c 149 if($spec->{INIT_META}){
150 foreach my $init_meta(@{$spec->{INIT_META}}){
151 $into->$init_meta(for_class => $into);
152 }
db9fc237 153
1ff34b4c 154 # _apply_meta_traits($into); # TODO
db9fc237 155 }
156
1ff34b4c 157 if(@exports){
158 foreach my $keyword(@exports){
159 no strict 'refs';
160 *{$into.'::'.$keyword} = $spec->{EXPORTS}{$keyword}
161 || confess(qq{The $package package does not export "$keyword"});
162 }
163 }
164 else{
165 my $default = $spec->{DEFAULT};
166 while(my($keyword, $code) = each %{$default}){
167 no strict 'refs';
168 *{$into.'::'.$keyword} = $code;
169 }
db9fc237 170 }
171 return;
172}
173
174# the entity of general unimport()
175sub do_unimport {
1ff34b4c 176 my($package, $arg) = @_;
db9fc237 177
1ff34b4c 178 my $spec = $SPEC{$package}
179 || confess("The package $package does not use Mouse::Exporter");
db9fc237 180
181 my $from = _get_caller_package($arg);
182
183 my $stash = do{
184 no strict 'refs';
185 \%{$from . '::'}
186 };
187
188 for my $keyword (@{ $spec->{REMOVABLES} }) {
4ee3190e 189 my $gv = \$stash->{$keyword};
190 if(ref($gv) eq 'GLOB' && *{$gv}{CODE} == $spec->{EXPORTS}{$keyword}){ # make sure it is from us
191 delete $stash->{$keyword};
192 }
db9fc237 193 }
194 return;
195}
196
197sub _get_caller_package {
198 my($arg) = @_;
199
200 # 2 extra level because it's called by import so there's a layer\r
201 # of indirection\r
202 my $offset = 1;\r
203
204 if(ref $arg){
205 return defined($arg->{into}) ? $arg->{into}
206 : defined($arg->{into_level}) ? scalar caller($offset + $arg->{into_level})
207 : scalar caller($offset);
208 }
209 else{
210 return scalar caller($offset);
211 }
212}
213
2141;
215
216__END__
217
218=head1 NAME
219
220Mouse - The Mouse Exporter
221
222=head1 SYNOPSIS
223
224 package MouseX::Foo;
225 use Mouse::Exporter;
226
227 Mouse::Exporter->setup_import_methods(
228
229 );
230
231=head1 DESCRIPTION
232
233
234=head1 SEE ALSO
235
236L<Moose::Exporter>
237
238=cut