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.003';
4              
5 8     8   27614 use strict;
  8         12  
  8         177  
6 8     8   22 use warnings;
  8         8  
  8         145  
7 8     8   2736 use mro ();
  8         4154  
  8         173  
8 8     8   2947 use Import::Into;
  8         14967  
  8         215  
9 8     8   35 use Module::Runtime qw( use_module );
  8         8  
  8         26  
10              
11             require Exporter;
12              
13             our @ISA = qw(Exporter);
14              
15             sub modules {
16 46     46 1 2161 my ( $class, $bundles, $args ) = @_;
17 46         49 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         41 for my $pkg ( reverse @{ mro::get_linear_isa( $class ) } ) {
  46         172  
23 8     8   595 no strict 'refs';
  8         9  
  8         226  
24 8     8   25 no warnings 'once';
  8         7  
  8         6310  
25              
26 151 100       224 if ( !$args->{bundles_only} ) {
27 145         103 push @modules, @{ $pkg . "::IMPORT_MODULES" };
  145         304  
28             }
29              
30 151         97 my %bundles = %{ $pkg . "::IMPORT_BUNDLES" };
  151         294  
31 23         19 push @modules, map { @{ $bundles{ $_ } } }
  23         60  
32 151         166 grep { exists $bundles{ $_ } }
  99         185  
33             @$bundles;
34             }
35              
36 46         127 return @modules;
37             }
38              
39             sub _parse_args {
40 46     46   54 my ( $class, @args ) = @_;
41 46         38 my @bundles;
42 46         100 while ( @args ) {
43 34 100       83 last if $args[0] =~ /^-/;
44 31         67 push @bundles, shift @args;
45             }
46 46         68 my %args = @args;
47 46         80 return ( \@bundles, \%args );
48             }
49              
50             sub import_bundle {
51 2     2 1 3749 my ( $class, @args ) = @_;
52 2         5 my ( $bundles, $args ) = $class->_parse_args( @args );
53              
54             # Add internal Import::Base args
55 2         5 $args->{package} = scalar caller(0);
56 2         3 $args->{bundles_only} = 1;
57              
58 2         5 my @modules = $class->modules( $bundles, $args );
59 2         5 $class->_import_modules( \@modules, $bundles, $args );
60             }
61              
62             sub import {
63 44     44   82871 my ( $class, @args ) = @_;
64 44         111 my ( $bundles, $args ) = $class->_parse_args( @args );
65              
66             # Add internal Import::Base args
67 44         91 $args->{package} = scalar caller(0);
68              
69 44         118 my @modules = $class->modules( $bundles, $args );
70 44         165 $class->_import_modules( \@modules, $bundles, $args );
71             }
72              
73             sub _import_modules {
74 46     46   46 my ( $class, $modules, $bundles, $args ) = @_;
75              
76             die "Argument to -exclude must be arrayref"
77 46 100 100     157 if $args->{-exclude} && ref $args->{-exclude} ne 'ARRAY';
78 45         52 my $exclude = {};
79 45 100       80 if ( $args->{-exclude} ) {
80 2         1 while ( @{ $args->{-exclude} } ) {
  4         10  
81 2         2 my $module = shift @{ $args->{-exclude} };
  2         2  
82 2 100       6 my $subs = ref $args->{-exclude}[0] eq 'ARRAY' ? shift @{ $args->{-exclude} } : undef;
  1         1  
83 2         4 $exclude->{ $module } = $subs;
84             }
85             }
86              
87             # Add internal Import::Base args
88 45   50     74 $args->{package} ||= scalar caller(0);
89              
90 45         75 my @modules = @$modules;
91 45         49 my @cb_args = ( $bundles, $args );
92              
93             # Prepare the modules to load
94             # First pass determines the order to load
95 45         62 my ( @first_load, @last_load );
96 45         72 while ( @modules ) {
97 145 100       215 if ( ref $modules[0] eq 'CODE' ) {
98 15         15 push @first_load, shift @modules;
99 15         26 next;
100             }
101              
102 130         101 my $thing = shift @modules;
103 130         103 my $module;
104             my $version;
105 130 100       188 if ( ref $thing eq 'HASH' ) {
106 4         9 ( $module, $version ) = %$thing;
107             }
108             else {
109 126         95 $module = $thing;
110             }
111 130 100       162 my $imports = ref $modules[0] eq 'ARRAY' ? shift @modules : [];
112              
113             # Determine the module order
114 130 100       222 if ( $module =~ /^
    100          
115 10         17 $module =~ s/^
116 10 50       14 if ( defined $version ) {
117 0         0 unshift @first_load, { $module => $version } => $imports;
118             }
119             else {
120 10         21 unshift @first_load, $module => $imports;
121             }
122             }
123             elsif ( $module =~ /^>/ ) {
124 10         12 $module =~ s/^>//;
125 10 50       11 if ( defined $version ) {
126 0         0 push @last_load, { $module => $version } => $imports;
127             }
128             else {
129 10         19 push @last_load, $module => $imports;
130             }
131             }
132             else {
133 110         205 push @first_load, $thing => $imports;
134             }
135             }
136              
137             # Second pass loads the modules
138 45         71 my @loads = ( @first_load, @last_load );
139 45         77 while ( my $load = shift @loads ) {
140 153         12587 my $module;
141             my $version;
142 153 100       255 if ( ref $load eq 'CODE' ) {
    100          
143 15         30 unshift @loads, $load->( @cb_args );
144 12         13057 next;
145             }
146             elsif ( ref $load eq 'HASH' ) {
147 4         9 ( $module, $version ) = %$load;
148             }
149             else {
150 134         124 $module = $load;
151             }
152              
153 138 100       203 my $imports = ref $loads[0] eq 'ARRAY' ? shift @loads : [];
154              
155 138 100       210 if ( exists $exclude->{ $module } ) {
156 2 100       4 if ( defined $exclude->{ $module } ) {
157 1         1 my @left;
158 1         2 for my $import ( @$imports ) {
159             push @left, $import
160 1 50       2 unless grep { $_ eq $import } @{ $exclude->{ $module } };
  1         3  
  1         2  
161             }
162 1         2 $imports = \@left;
163             }
164             else {
165 1         2 next;
166             }
167             }
168              
169 137         106 my $method = 'import::into';
170 137 100       218 if ( $module =~ /^-/ ) {
171 34         29 $method = 'unimport::out_of';
172 34         61 $module =~ s/^-//;
173             }
174              
175 137 100       578 if ($module->isa("Import::Base")) {
176 2         2 $module->export_to_level( 2, $module, @{ $imports } );
  2         152  
177              
178 2         71 next;
179             }
180              
181 135         242 use_module( $module );
182 135 100       5723 if ( defined $version ) {
183 4         8 $module->$method( { level => 2, version => $version }, @{ $imports } );
  4         14  
184             }
185             else {
186 131         100 $module->$method( 2, @{ $imports } );
  131         368  
187             }
188             }
189             }
190              
191             1;
192              
193             __END__