File Coverage

blib/lib/SelfLoader.pm
Criterion Covered Total %
statement 101 118 85.5
branch 33 54 61.1
condition 7 9 77.7
subroutine 16 19 84.2
pod 1 4 25.0
total 158 204 77.4


line stmt bran cond sub pod time code
1             package SelfLoader;
2 2     2   1249 use 5.008;
  2         9  
  2         80  
3 2     2   10 use strict;
  2         3  
  2         64  
4 2     2   2198 use IO::Handle;
  2         17169  
  2         133  
5             our $VERSION = "1.20";
6              
7             # The following bit of eval-magic is necessary to make this work on
8             # perls < 5.009005.
9 2     2   19 use vars qw/$AttrList/;
  2         5  
  2         171  
10             BEGIN {
11 2 50   2   11 if ($] > 5.009004) {
12 2     2   115 eval <<'NEWERPERL';
  2         47  
  2         7  
  2         173  
13             use 5.009005; # due to new regexp features
14             # allow checking for valid ': attrlist' attachments
15             # see also AutoSplit
16             $AttrList = qr{
17             \s* : \s*
18             (?:
19             # one attribute
20             (?> # no backtrack
21             (?! \d) \w+
22             (? \( (?: [^()]++ | (?&nested)++ )*+ \) ) ?
23             )
24             (?: \s* : \s* | \s+ (?! :) )
25             )*
26             }x;
27              
28             NEWERPERL
29             }
30             else {
31 0         0 eval <<'OLDERPERL';
32             # allow checking for valid ': attrlist' attachments
33             # (we use 'our' rather than 'my' here, due to the rather complex and buggy
34             # behaviour of lexicals with qr// and (??{$lex}) )
35             our $nested;
36             $nested = qr{ \( (?: (?> [^()]+ ) | (??{ $nested }) )* \) }x;
37             our $one_attr = qr{ (?> (?! \d) \w+ (?:$nested)? ) (?:\s*\:\s*|\s+(?!\:)) }x;
38             $AttrList = qr{ \s* : \s* (?: $one_attr )* }x;
39             OLDERPERL
40             }
41             }
42 2     2   8 use Exporter;
  2         4  
  2         820  
43             our @ISA = qw(Exporter);
44             our @EXPORT = qw(AUTOLOAD);
45 0     0 1 0 sub Version {$VERSION}
46             sub DEBUG () { 0 }
47              
48             my %Cache; # private cache for all SelfLoader's client packages
49              
50             # in croak and carp, protect $@ from "require Carp;" RT #40216
51              
52 4     4 0 6 sub croak { { local $@; require Carp; } goto &Carp::croak }
  4         7  
  4         33  
  4         1001  
53 0     0 0 0 sub carp { { local $@; require Carp; } goto &Carp::carp }
  0         0  
  0         0  
  0         0  
54              
55             AUTOLOAD {
56 11     11   283 our $AUTOLOAD;
57 11         13 print STDERR "SelfLoader::AUTOLOAD for $AUTOLOAD\n" if DEBUG;
58 11         24 my $SL_code = $Cache{$AUTOLOAD};
59 11         17 my $save = $@; # evals in both AUTOLOAD and _load_stubs can corrupt $@
60 11 100       28 unless ($SL_code) {
61             # Maybe this pack had stubs before __DATA__, and never initialized.
62             # Or, this maybe an automatic DESTROY method call when none exists.
63 6         43 $AUTOLOAD =~ m/^(.*)::/;
64 6 100       97 SelfLoader->_load_stubs($1) unless exists $Cache{"${1}::
65 6         15 $SL_code = $Cache{$AUTOLOAD};
66 6 50 66     36 $SL_code = "sub $AUTOLOAD { }"
67             if (!$SL_code and $AUTOLOAD =~ m/::DESTROY$/);
68 6 100       29 croak "Undefined subroutine $AUTOLOAD" unless $SL_code;
69             }
70 8         10 print STDERR "SelfLoader::AUTOLOAD eval: $SL_code\n" if DEBUG;
71              
72             {
73 2     2   17 no strict;
  2         4  
  2         353  
  8         13  
74 8         478 eval $SL_code;
75             }
76 8 100       27 if ($@) {
77 1         8 $@ =~ s/ at .*\n//;
78 1         5 croak $@;
79             }
80 7         10 $@ = $save;
81 7 50       25 defined(&$AUTOLOAD) || die "SelfLoader inconsistency error";
82 7         15 delete $Cache{$AUTOLOAD};
83 7         1612 goto &$AUTOLOAD
84             }
85              
86 0     0 0 0 sub load_stubs { shift->_load_stubs((caller)[0]) }
87              
88             sub _load_stubs {
89             # $endlines is used by Devel::SelfStubber to capture lines after __END__
90 3     3   9 my($self, $callpack, $endlines) = @_;
91 2     2   11 no strict "refs";
  2         3  
  2         105  
92 3         6 my $fh = \*{"${callpack}::DATA"};
  3         18  
93 2     2   18 use strict;
  2         2  
  2         1440  
94 3         47 my $currpack = $callpack;
95 3         7 my($line,$name,@lines, @stubs, $protoype);
96              
97 3         5 print STDERR "SelfLoader::load_stubs($callpack)\n" if DEBUG;
98 3 50       19 croak("$callpack doesn't contain an __DATA__ token")
99             unless defined fileno($fh);
100             # Protect: fork() shares the file pointer between the parent and the kid
101 3 50       31 if(sysseek($fh, tell($fh), 0)) {
102 3 50       169 open my $nfh, '<&', $fh or croak "reopen: $!";# dup() the fd
103 3 50       29 close $fh or die "close: $!"; # autocloses, but be paranoid
104 3 50       59 open $fh, '<&', $nfh or croak "reopen2: $!"; # dup() the fd "back"
105 3 50       20 close $nfh or die "close after reopen: $!"; # autocloses, but be paranoid
106 3         30 $fh->untaint;
107             }
108 3         38 $Cache{"${currpack}::
109              
110 3         16 local($/) = "\n";
111 3   100     104 while(defined($line = <$fh>) and $line !~ m/^__END__/) {
112 43 100       808 if ($line =~ m/^\s*sub\s+([\w:]+)\s*((?:\([\\\$\@\%\&\*\;]*\))?(?:$AttrList)?)/) {
    100          
113 8         33 push(@stubs, $self->_add_to_cache($name, $currpack, \@lines, $protoype));
114 8         21 $protoype = $2;
115 8         15 @lines = ($line);
116 8 50       39 if (index($1,'::') == -1) { # simple sub name
117 8         61 $name = "${currpack}::$1";
118             } else { # sub name with package
119 0         0 $name = $1;
120 0         0 $name =~ m/^(.*)::/;
121 0 0       0 if (defined(&{"${1}::AUTOLOAD"})) {
  0         0  
122 0 0       0 \&{"${1}::AUTOLOAD"} == \&SelfLoader::AUTOLOAD ||
  0         0  
123             die 'SelfLoader Error: attempt to specify Selfloading',
124             " sub $name in non-selfloading module $1";
125             } else {
126 0         0 $self->export($1,'AUTOLOAD');
127             }
128             }
129             } elsif ($line =~ m/^package\s+([\w:]+)/) { # A package declared
130 1         6 push(@stubs, $self->_add_to_cache($name, $currpack, \@lines, $protoype));
131 1         5 $self->_package_defined($line);
132 1         2 $name = '';
133 1         3 @lines = ();
134 1         2 $currpack = $1;
135 1         4 $Cache{"${currpack}::
136 1 50       1 if (defined(&{"${1}::AUTOLOAD"})) {
  1         18  
137 0 0       0 \&{"${1}::AUTOLOAD"} == \&SelfLoader::AUTOLOAD ||
  0         0  
138             die 'SelfLoader Error: attempt to specify Selfloading',
139             " package $currpack which already has AUTOLOAD";
140             } else {
141 1         179 $self->export($currpack,'AUTOLOAD');
142             }
143             } else {
144 34         214 push(@lines,$line);
145             }
146             }
147 3 100 66     21 if (defined($line) && $line =~ /^__END__/) { # __END__
148 2 100       17 unless ($line =~ /^__END__\s*DATA/) {
149 1 50       4 if ($endlines) {
150             # Devel::SelfStubber would like us to capture the lines after
151             # __END__ so it can write out the entire file
152 0         0 @$endlines = <$fh>;
153             }
154 1         20 close($fh);
155             }
156             }
157 3         16 push(@stubs, $self->_add_to_cache($name, $currpack, \@lines, $protoype));
158 2     2   10 no strict;
  2         3  
  2         479  
159 3 50       246 eval join('', @stubs) if @stubs;
160             }
161              
162              
163             sub _add_to_cache {
164 12     12   28 my($self,$fullname,$pack,$lines, $protoype) = @_;
165 12 100       35 return () unless $fullname;
166 8 50       23 carp("Redefining sub $fullname")
167             if exists $Cache{$fullname};
168 8         41 $Cache{$fullname} = join('', "\n\#line 1 \"sub $fullname\"\npackage $pack; ", @$lines);
169             #$Cache{$fullname} = join('', "package $pack; ",@$lines);
170 8         9 print STDERR "SelfLoader cached $fullname: $Cache{$fullname}" if DEBUG;
171             # return stub to be eval'd
172 8 50       37 defined($protoype) ? "sub $fullname $protoype;" : "sub $fullname;"
173             }
174              
175 1     1   1 sub _package_defined {}
176              
177             1;
178             __END__