File Coverage

blib/lib/deferred.pm
Criterion Covered Total %
statement 45 50 90.0
branch 18 22 81.8
condition 2 3 66.6
subroutine 8 8 100.0
pod n/a
total 73 83 87.9


line stmt bran cond sub pod time code
1             package deferred;
2 5     5   100393 use strict;
  5         12  
  5         2835  
3              
4             our $VERSION = "0.01";
5              
6             # Modules the user has requested to defer
7             my @enabled;
8             # Modules we've half loaded
9             my %half_loaded;
10              
11             sub import {
12 5     5   37 my $class = shift;
13              
14 5 100       19 push @enabled, map { ref $_ ? $_ : qr/^$_$/ } @_;
  4         111  
15             }
16              
17             sub unimport {
18 2     2   3794 my $class = shift;
19              
20 2 100 66     25 my $discard = @_ && $_[0] eq '-discard' ? pop : 0;
21              
22 2 50       8 if(@_) {
23 0 0       0 my @disable = map { ref $_ ? $_ : qr/^$_$/ } @_;
  0         0  
24              
25 0         0 for my $disable(@disable) {
26 0         0 @enabled = grep { $_ ne $disable } @enabled;
  0         0  
27             }
28             } else {
29 2         12 @enabled = ();
30              
31 2 100       9 if(!$discard) {
32 1         4 for my $class(keys %half_loaded) {
33 1         5 _load($class);
34             }
35             }
36              
37 2         61 %half_loaded = ();
38             }
39             }
40              
41             unshift @INC, my $inc_ref = sub {
42             my(undef, $file) = @_;
43              
44             # We get a filename here, we let the user specify a module name, so convert
45             # it back.
46             (my $module = $file) =~ s{/}{::}g;
47             $module =~ s/\.pm$//;
48              
49             if(caller =~ /^(?:base|parent)/) {
50             # When these modules load something they really do mean it
51             return;
52             }
53              
54             for my $enabled(@enabled) {
55             if($module =~ $enabled) {
56             $half_loaded{$module} = join ":", (caller)[1,2];
57              
58 4     4   20 open my $fh, "<", \"1";
  4         8  
  4         25  
59             return $fh;
60             }
61             }
62              
63             return;
64             };
65              
66             sub UNIVERSAL::AUTOLOAD {
67 4     4   1771 my $load = $UNIVERSAL::AUTOLOAD;
68              
69 4         39 my($class, $method) = ($load =~ /^(.*)::(.*)$/);
70 4 50       21 return if $method eq 'DESTROY';
71              
72 4 100       22 _load($class) if exists $half_loaded{$class};
73              
74 5     5   39 no warnings 'once';
  5         10  
  5         299  
75 5     5   58 no strict 'refs';
  5         8  
  5         1323  
76              
77 3 100       5 if(*{$load}{CODE}) {
  3 100       46  
78 1         6 goto &$load;
79             } elsif(my $can = $class->can($method)) {
80 1         6 goto &$can;
81             } else {
82             # Really doesn't exist
83 1         11 require Carp;
84 1         278 Carp::croak("Undefined subroutine/method called ($load)");
85             }
86             }
87              
88             sub _load {
89 4     4   9 my $class = shift;
90              
91             # Avoid the need to reimplement @INC searching
92 4 100       13 local @INC = grep { !ref || $_ != $inc_ref } @INC;
  48         139  
93              
94 4         19 (my $file = $class) =~ s{::}{/}g;
95 4         8 $file .= ".pm";
96 4         502 local %INC = %INC;
97 4         23 delete $INC{$file};
98              
99 4         12 my $orig = delete $half_loaded{$class};
100 4         8 my $ok = eval { require $file };
  4         2894  
101              
102 4 100       680 die "deferred load of $class failed (originally loaded at $orig):\n$@"
103             if !$ok;
104 3         38 $ok;
105             }
106              
107             1;
108              
109             __END__