File Coverage

blib/lib/Mouse/Exporter.pm
Criterion Covered Total %
statement 130 134 97.0
branch 50 54 92.5
condition 10 28 35.7
subroutine 17 19 89.4
pod 2 4 50.0
total 209 239 87.4


line stmt bran cond sub pod time code
1             package Mouse::Exporter;
2 284     284   1060 use strict;
  284         354  
  284         6929  
3 284     284   954 use warnings;
  284         349  
  284         5939  
4 284     284   928 use Carp ();
  284         320  
  284         91905  
5              
6             my %SPEC;
7              
8             # it must be "require", because Mouse::Util depends on Mouse::Exporter,
9             # which depends on Mouse::Util::import()
10             require Mouse::Util;
11              
12             sub import{
13 974     974   7952 strict->import;
14 974         14457 warnings->import('all', FATAL => 'recursion');
15 974         34967 return;
16             }
17              
18              
19             sub setup_import_methods{
20 975     975 1 8534 my($class, %args) = @_;
21              
22 975   33     7950 my $exporting_package = $args{exporting_package} ||= caller();
23              
24 975         9578 my($import, $unimport) = $class->build_import_methods(%args);
25              
26             Mouse::Util::install_subroutines($exporting_package,
27             import => $import,
28             unimport => $unimport,
29              
30             export_to_level => sub {
31 1     1   255 my($package, $level, undef, @args) = @_; # the third argument is redundant
        1      
        1      
        0      
32 1         3 $package->import({ into_level => $level + 1 }, @args);
33             },
34             export => sub {
35 1     1   918 my($package, $into, @args) = @_;
        1      
        1      
        0      
36 1         6 $package->import({ into => $into }, @args);
37             },
38 975         11862 );
39 975         2715 return;
40             }
41              
42             sub build_import_methods{
43 975     975 1 2817 my($self, %args) = @_;
44              
45 975   33     4886 my $exporting_package = $args{exporting_package} ||= caller();
46              
47 975         2069 $SPEC{$exporting_package} = \%args;
48              
49             # canonicalize args
50 975         4446 my @export_from;
51 975 100       3810 if($args{also}){
52 7         9 my %seen;
53 7         12 my @stack = ($exporting_package);
54              
55 7         19 while(my $current = shift @stack){
56 15         15 push @export_from, $current;
57              
58 15 100       51 my $also = $SPEC{$current}{also} or next;
59 8 100       26 push @stack, grep{ !$seen{$_}++ } ref($also) ? @{ $also } : $also;
  8         33  
  3         3  
60             }
61             }
62             else{
63 968         1615 @export_from = ($exporting_package);
64             }
65              
66 975         1051 my %exports;
67             my @removables;
68 0         0 my @all;
69              
70 0         0 my @init_meta_methods;
71              
72 975         2907 foreach my $package(@export_from){
73 983 50       3234 my $spec = $SPEC{$package} or next;
74              
75 983 100       4892 if(my $as_is = $spec->{as_is}){
76 978         1528 foreach my $thingy (@{$as_is}){
  978         2194  
77 13936         9223 my($code_package, $code_name, $code);
78              
79 13936 100       14687 if(ref($thingy)){
80 763         701 $code = $thingy;
81 763         2486 ($code_package, $code_name) = Mouse::Util::get_code_info($code);
82             }
83             else{
84 13173         10041 $code_package = $package;
85 13173         8592 $code_name = $thingy;
86 284     284   1868 no strict 'refs';
  284         1004  
  284         194815  
87 13173         7727 $code = \&{ $code_package . '::' . $code_name };
  13173         36457  
88             }
89              
90 13936         14750 push @all, $code_name;
91 13936         13834 $exports{$code_name} = $code;
92 13936 100       20199 if($code_package eq $package){
93 13174         16205 push @removables, $code_name;
94             }
95             }
96             }
97              
98 983 100       12899 if(my $init_meta = $package->can('init_meta')){
99 384 50       1147 if(!grep{ $_ == $init_meta } @init_meta_methods){
  3         8  
100 384         819 push @init_meta_methods, $init_meta;
101             }
102             }
103             }
104 975         2995 $args{EXPORTS} = \%exports;
105 975         1939 $args{REMOVABLES} = \@removables;
106              
107 975   50     4838 $args{groups}{all} ||= \@all;
108              
109 975 100       1998 if(my $default_list = $args{groups}{default}){
110 284         321 my %default;
111 284         347 foreach my $keyword(@{$default_list}){
  284         518  
112 0   0     0 $default{$keyword} = $exports{$keyword}
113             || Carp::confess(qq{The $exporting_package package does not export "$keyword"});
114             }
115 284         522 $args{DEFAULT} = \%default;
116             }
117             else{
118 691   50     2630 $args{groups}{default} ||= \@all;
119 691         1029 $args{DEFAULT} = $args{EXPORTS};
120             }
121              
122 975 100       3441 if(@init_meta_methods){
123 381         577 $args{INIT_META} = \@init_meta_methods;
124             }
125              
126 975         2850 return (\&do_import, \&do_unimport);
127             }
128              
129             # the entity of general import()
130             sub do_import {
131 4175     4175 0 579807 my($package, @args) = @_;
132              
133 4175   33     10663 my $spec = $SPEC{$package}
134             || Carp::confess("The package $package package does not use Mouse::Exporter");
135              
136 4175 100       10323 my $into = _get_caller_package(ref($args[0]) ? shift @args : undef);
137              
138 4175         14324 my @exports;
139             my @traits;
140              
141 4175         7870 while(@args){
142 3394         3503 my $arg = shift @args;
143 3394 100       13316 if($arg =~ s/^-//){
    100          
144 17 50       31 if($arg eq 'traits'){
145 17 100       48 push @traits, ref($args[0]) ? @{shift(@args)} : shift(@args);
  10         33  
146             }
147             else {
148 0         0 Mouse::Util::not_supported("-$arg");
149             }
150             }
151             elsif($arg =~ s/^://){
152 2470   33     5440 my $group = $spec->{groups}{$arg}
153             || Carp::confess(qq{The $package package does not export the group "$arg"});
154 2470         2056 push @exports, @{$group};
  2470         7478  
155             }
156             else{
157 907         1851 push @exports, $arg;
158             }
159             }
160              
161 4175         16731 strict->import;
162 4175         51828 warnings->import('all', FATAL => 'recursion');
163              
164 4175 100       10525 if($spec->{INIT_META}){
    100          
165 763         812 my $meta;
166 763         746 foreach my $init_meta(@{$spec->{INIT_META}}){
  763         1459  
167 768         2166 $meta = $package->$init_meta(for_class => $into);
168             }
169              
170 763 100       1636 if(@traits){
171 16         57 my $type = (split /::/, ref $meta)[-1]; # e.g. "Class" for "My::Meta::Class"
172             @traits = map{
173 16 100       27 ref($_)
  19         56  
174             ? $_
175             : Mouse::Util::resolve_metaclass_alias($type => $_, trait => 1)
176             } @traits;
177              
178 16         425 require Mouse::Util::MetaRole;
179 16 100       44 Mouse::Util::MetaRole::apply_metaroles(
180             for => $into,
181             Mouse::Util::is_a_metarole($into->meta)
182             ? (role_metaroles => { role => \@traits })
183             : (class_metaroles => { class => \@traits }),
184             );
185             }
186             }
187             elsif(@traits){
188 1         21 Carp::confess("Cannot provide traits when $package does not have an init_meta() method");
189             }
190              
191 4174 100       5873 if(@exports){
192 2787         2123 my @export_table;
193 2787         2956 foreach my $keyword(@exports){
194             push @export_table,
195 10799   33     20408 $keyword => ($spec->{EXPORTS}{$keyword}
196             || Carp::confess(qq{The $package package does not export "$keyword"})
197             );
198             }
199 2787         27217 Mouse::Util::install_subroutines($into, @export_table);
200             }
201             else{
202 1387         1362 Mouse::Util::install_subroutines($into, %{$spec->{DEFAULT}});
  1387         16949  
203             }
204 4174         769681 return;
205             }
206              
207             # the entity of general unimport()
208             sub do_unimport {
209 64     64 0 10777 my($package, $arg) = @_;
210              
211 64   33     177 my $spec = $SPEC{$package}
212             || Carp::confess("The package $package does not use Mouse::Exporter");
213              
214 64         107 my $from = _get_caller_package($arg);
215              
216 64         265 my $stash = do{
217 284     284   1351 no strict 'refs';
  284         1091  
  284         48557  
218 64         57 \%{$from . '::'}
  64         181  
219             };
220              
221 64         72 for my $keyword (@{ $spec->{REMOVABLES} }) {
  64         133  
222 693 100       924 next if !exists $stash->{$keyword};
223 685         567 my $gv = \$stash->{$keyword};
224              
225             # remove what is from us
226 685 100 66     983 if(ref($gv) eq 'GLOB' && *{$gv}{CODE} == $spec->{EXPORTS}{$keyword}){
  685         1609  
227 684         1040 delete $stash->{$keyword};
228             }
229             }
230 64         19281 return;
231             }
232              
233             sub _get_caller_package {
234 4239     4239   3730 my($arg) = @_;
235              
236             # We need one extra level because it's called by import so there's a layer
237             # of indirection
238 4239 100       5910 if(ref $arg){
239             return defined($arg->{into}) ? $arg->{into}
240             : defined($arg->{into_level}) ? scalar caller(1 + $arg->{into_level})
241 852 50       2095 : scalar caller(1);
    100          
242             }
243             else{
244 3387         7434 return scalar caller(1);
245             }
246             }
247              
248             1;
249             __END__