File Coverage

blib/lib/Import/Base.pm
Criterion Covered Total %
statement 118 120 98.3
branch 39 42 92.8
condition 4 5 80.0
subroutine 12 12 100.0
pod 2 2 100.0
total 175 181 96.6


line stmt bran cond sub pod time code
1             package Import::Base;
2             # ABSTRACT: Import a set of modules into the calling module
3             our $VERSION = '1.004';
4              
5 8     8   35109 use strict;
  8         15  
  8         177  
6 8     8   29 use warnings;
  8         11  
  8         154  
7 8     8   38 use mro ();
  8         13  
  8         122  
8 8     8   3045 use Import::Into;
  8         16711  
  8         224  
9 8     8   41 use Module::Runtime qw( use_module );
  8         13  
  8         24  
10              
11             require Exporter;
12              
13             our @ISA = qw(Exporter);
14              
15             sub modules {
16 46     46 1 3718 my ( $class, $bundles, $args ) = @_;
17 46         87 my @modules = ();
18              
19             # Find all the modules from the static API
20             # Reverse the array to allow more-specific classes to override
21             # less-specific ones
22 46         65 for my $pkg ( reverse @{ mro::get_linear_isa( $class ) } ) {
  46         232  
23 8     8   895 no strict 'refs';
  8         10  
  8         257  
24 8     8   35 no warnings 'once';
  8         10  
  8         7558  
25              
26 151 100       272 if ( !$args->{bundles_only} ) {
27 145         155 push @modules, @{ $pkg . "::IMPORT_MODULES" };
  145         372  
28             }
29              
30 151         160 my %bundles = %{ $pkg . "::IMPORT_BUNDLES" };
  151         403  
31 23         34 push @modules, map { @{ $bundles{ $_ } } }
  23         77  
32 151         251 grep { exists $bundles{ $_ } }
  99         229  
33             @$bundles;
34             }
35              
36 46         146 return @modules;
37             }
38              
39             sub _parse_args {
40 46     46   81 my ( $class, @args ) = @_;
41 46         62 my @bundles;
42 46         108 while ( @args ) {
43 34 100       99 last if $args[0] =~ /^-/;
44 31         81 push @bundles, shift @args;
45             }
46 46         75 my %args = @args;
47 46         149 return ( \@bundles, \%args );
48             }
49              
50             sub import_bundle {
51 2     2 1 6758 my ( $class, @args ) = @_;
52 2         13 my ( $bundles, $args ) = $class->_parse_args( @args );
53              
54             # Add internal Import::Base args
55 2         5 $args->{package} = scalar caller(0);
56 2         4 $args->{bundles_only} = 1;
57              
58 2         4 my @modules = $class->modules( $bundles, $args );
59 2         6 $class->_import_modules( \@modules, $bundles, $args );
60             }
61              
62             sub import {
63 44     44   144211 my ( $class, @args ) = @_;
64 44         133 my ( $bundles, $args ) = $class->_parse_args( @args );
65              
66             # Add internal Import::Base args
67 44         111 $args->{package} = scalar caller(0);
68              
69 44         137 my @modules = $class->modules( $bundles, $args );
70 44         200 $class->_import_modules( \@modules, $bundles, $args );
71             }
72              
73             sub _import_modules {
74 46     46   89 my ( $class, $modules, $bundles, $args ) = @_;
75              
76             die "Argument to -exclude must be arrayref"
77 46 100 100     138 if $args->{-exclude} && ref $args->{-exclude} ne 'ARRAY';
78 45         65 my $exclude = {};
79 45 100       89 if ( $args->{-exclude} ) {
80 2         2 while ( @{ $args->{-exclude} } ) {
  4         9  
81 2         3 my $module = shift @{ $args->{-exclude} };
  2         4  
82 2 100       5 my $subs = ref $args->{-exclude}[0] eq 'ARRAY' ? shift @{ $args->{-exclude} } : undef;
  1         2  
83 2         4 $exclude->{ $module } = $subs;
84             }
85             }
86              
87             # Add internal Import::Base args
88 45   50     103 $args->{package} ||= scalar caller(0);
89              
90 45         85 my @modules = @$modules;
91 45         89 my @cb_args = ( $bundles, $args );
92              
93             # Prepare the modules to load
94             # First pass determines the order to load
95 45         58 my ( @first_load, @last_load );
96 45         79 while ( @modules ) {
97 145 100       277 if ( ref $modules[0] eq 'CODE' ) {
98 15         21 push @first_load, shift @modules;
99 15         26 next;
100             }
101              
102 130         159 my $thing = shift @modules;
103 130         158 my $module;
104             my $version;
105 130 100       213 if ( ref $thing eq 'HASH' ) {
106 4         13 ( $module, $version ) = %$thing;
107             }
108             else {
109 126         175 $module = $thing;
110             }
111 130 100       247 my $imports = ref $modules[0] eq 'ARRAY' ? shift @modules : [];
112              
113             # Determine the module order
114 130 100       398 if ( $module =~ /^
    100          
115 10         25 $module =~ s/^
116 10 50       13 if ( defined $version ) {
117 0         0 unshift @first_load, { $module => $version } => $imports;
118             }
119             else {
120 10         25 unshift @first_load, $module => $imports;
121             }
122             }
123             elsif ( $module =~ /^>/ ) {
124 10         20 $module =~ s/^>//;
125 10 50       17 if ( defined $version ) {
126 0         0 push @last_load, { $module => $version } => $imports;
127             }
128             else {
129 10         20 push @last_load, $module => $imports;
130             }
131             }
132             else {
133 110         240 push @first_load, $thing => $imports;
134             }
135             }
136              
137             # Second pass loads the modules
138 45         99 my @loads = ( @first_load, @last_load );
139 45         110 while ( my $load = shift @loads ) {
140 153         15493 my $module;
141             my $version;
142 153 100       336 if ( ref $load eq 'CODE' ) {
    100          
143 15         34 unshift @loads, $load->( @cb_args );
144 12         17884 next;
145             }
146             elsif ( ref $load eq 'HASH' ) {
147 4         10 ( $module, $version ) = %$load;
148             }
149             else {
150 134         169 $module = $load;
151             }
152              
153 138 100       249 my $imports = ref $loads[0] eq 'ARRAY' ? shift @loads : [];
154              
155 138 100       268 if ( exists $exclude->{ $module } ) {
156 2 100       6 if ( defined $exclude->{ $module } ) {
157 1         1 my @left;
158 1         3 for my $import ( @$imports ) {
159             push @left, $import
160 1 50       1 unless grep { $_ eq $import } @{ $exclude->{ $module } };
  1         4  
  1         2  
161             }
162 1         2 $imports = \@left;
163             }
164             else {
165 1         3 next;
166             }
167             }
168              
169 137         170 my $method = 'import::into';
170 137 100       282 if ( $module =~ /^-/ ) {
171 34         46 $method = 'unimport::out_of';
172 34         79 $module =~ s/^-//;
173             }
174              
175 137 100       755 if ($module->isa("Import::Base")) {
176 2         3 $module->export_to_level( 2, $module, @{ $imports } );
  2         130  
177              
178 2         71 next;
179             }
180              
181 135         337 use_module( $module );
182 135 100       7168 if ( defined $version ) {
183 4         13 $module->$method( { level => 2, version => $version }, @{ $imports } );
  4         16  
184             }
185             else {
186 131         156 $module->$method( 2, @{ $imports } );
  131         426  
187             }
188             }
189             }
190              
191             1;
192              
193             __END__