File Coverage

blib/lib/SelfLoader.pm
Criterion Covered Total %
statement 98 115 85.2
branch 34 54 62.9
condition 8 9 88.8
subroutine 17 20 85.0
pod 1 4 25.0
total 158 202 78.2


line stmt bran cond sub pod time code
1             package SelfLoader;
2 2     2   368 use 5.008;
  2         9  
3 2     2   12 use strict;
  2         5  
  2         51  
4 2     2   785 use IO::Handle;
  2         11741  
  2         143  
5             our $VERSION = "1.24";
6              
7             # The following bit of eval-magic is necessary to make this work on
8             # perls < 5.009005.
9 2     2   15 use vars qw/$AttrList/;
  2         5  
  2         201  
10             BEGIN {
11 2 50   2   15 if ($] > 5.009004) {
12 2     2   131 eval <<'NEWERPERL';
  2         47  
  2         7  
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   17 use Exporter;
  2         6  
  2         869  
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         6  
  4         23  
  4         470  
53 0     0 0 0 sub carp { { local $@; require Carp; } goto &Carp::carp }
  0         0  
  0         0  
  0         0  
54              
55             AUTOLOAD {
56 12     12   208 our $AUTOLOAD;
57 12         14 print STDERR "SelfLoader::AUTOLOAD for $AUTOLOAD\n" if DEBUG;
58 12         18 my $SL_code = $Cache{$AUTOLOAD};
59 12         18 my $save = $@; # evals in both AUTOLOAD and _load_stubs can corrupt $@
60 12 100       22 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 7         34 $AUTOLOAD =~ m/^(.*)::/;
64 7 100       37 SelfLoader->_load_stubs($1) unless exists $Cache{"${1}::
65 7         19 $SL_code = $Cache{$AUTOLOAD};
66 7 100 100     28 $SL_code = "sub $AUTOLOAD { }"
67             if (!$SL_code and $AUTOLOAD =~ m/::DESTROY$/);
68 7 100       21 croak "Undefined subroutine $AUTOLOAD" unless $SL_code;
69             }
70 9         10 print STDERR "SelfLoader::AUTOLOAD eval: $SL_code\n" if DEBUG;
71              
72             {
73 2     2   18 no strict;
  2         5  
  2         559  
  9         12  
74 9     1   386 eval $SL_code;
75             }
76 9 100       35 if ($@) {
77 1         11 $@ =~ s/ at .*\n//;
78 1         6 croak $@;
79             }
80 8         15 $@ = $save;
81 8 50       20 defined(&$AUTOLOAD) || die "SelfLoader inconsistency error";
82 8         12 delete $Cache{$AUTOLOAD};
83 8         801 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   11 my($self, $callpack, $endlines) = @_;
91 2     2   18 no strict "refs";
  2         7  
  2         151  
92 3         4 my $fh = \*{"${callpack}::DATA"};
  3         11  
93 2     2   29 use strict;
  2         6  
  2         1703  
94 3         4 my $currpack = $callpack;
95 3         6 my($line,$name,@lines, @stubs, $protoype);
96              
97 3         5 print STDERR "SelfLoader::load_stubs($callpack)\n" if DEBUG;
98 3 50       10 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       63 open my $nfh, '<&', $fh or croak "reopen: $!";# dup() the fd
103 3 50       14 close $fh or die "close: $!"; # autocloses, but be
104             # paranoid
105 3 50       23 open $fh, '<&', $nfh or croak "reopen2: $!"; # dup() the fd "back"
106 3 50       11 close $nfh or die "close after reopen: $!"; # autocloses, but be
107             # paranoid
108 3         25 $fh->untaint;
109             }
110 3         14 $Cache{"${currpack}::
111              
112 3         13 local($/) = "\n";
113 3   100     57 while(defined($line = <$fh>) and $line !~ m/^__END__/) {
114 43 100       424 if ($line =~ m/ ^\s* # indentation
    100          
115             sub\s+([\w:]+)\s* # 'sub' and sub name
116             (
117             (?:\([\\\$\@\%\&\*\;]*\))? # optional prototype sigils
118             (?:$AttrList)? # optional attribute list
119             )/x) {
120 8         30 push(@stubs, $self->_add_to_cache($name, $currpack,
121             \@lines, $protoype));
122 8         19 $protoype = $2;
123 8         21 @lines = ($line);
124 8 50       27 if (index($1,'::') == -1) { # simple sub name
125 8         49 $name = "${currpack}::$1";
126             } else { # sub name with package
127 0         0 $name = $1;
128 0         0 $name =~ m/^(.*)::/;
129 0 0       0 if (defined(&{"${1}::AUTOLOAD"})) {
  0         0  
130 0 0       0 \&{"${1}::AUTOLOAD"} == \&SelfLoader::AUTOLOAD ||
  0         0  
131             die 'SelfLoader Error: attempt to specify Selfloading',
132             " sub $name in non-selfloading module $1";
133             } else {
134 0         0 $self->export($1,'AUTOLOAD');
135             }
136             }
137             } elsif ($line =~ m/^package\s+([\w:]+)/) { # A package declared
138 1         3 push(@stubs, $self->_add_to_cache($name, $currpack,
139             \@lines, $protoype));
140 1         4 $self->_package_defined($line);
141 1         2 $name = '';
142 1         2 @lines = ();
143 1         2 $currpack = $1;
144 1         3 $Cache{"${currpack}::
145 1 50       2 if (defined(&{"${1}::AUTOLOAD"})) {
  1         6  
146 0 0       0 \&{"${1}::AUTOLOAD"} == \&SelfLoader::AUTOLOAD ||
  0         0  
147             die 'SelfLoader Error: attempt to specify Selfloading',
148             " package $currpack which already has AUTOLOAD";
149             } else {
150 1         63 $self->export($currpack,'AUTOLOAD');
151             }
152             } else {
153 34         213 push(@lines,$line);
154             }
155             }
156 3 100 66     18 if (defined($line) && $line =~ /^__END__/) { # __END__
157 2 100       5 unless ($line =~ /^__END__\s*DATA/) {
158 1 50       3 if ($endlines) {
159             # Devel::SelfStubber would like us to capture the lines after
160             # __END__ so it can write out the entire file
161 0         0 @$endlines = <$fh>;
162             }
163 1         8 close($fh);
164             }
165             }
166 3         11 push(@stubs, $self->_add_to_cache($name, $currpack, \@lines, $protoype));
167 2     2   19 no strict;
  2         5  
  2         556  
168 3 50       169 eval join('', @stubs) if @stubs;
169             }
170              
171              
172             sub _add_to_cache {
173 12     12   34 my($self,$fullname,$pack,$lines, $protoype) = @_;
174 12 100       28 return () unless $fullname;
175             carp("Redefining sub $fullname")
176 8 50       18 if exists $Cache{$fullname};
177 8         34 $Cache{$fullname} = join('',
178             "\n\#line 1 \"sub $fullname\"\npackage $pack; ",
179             @$lines);
180             #$Cache{$fullname} = join('', "package $pack; ",@$lines);
181 8         12 print STDERR "SelfLoader cached $fullname: $Cache{$fullname}" if DEBUG;
182             # return stub to be eval'd
183 8 50       30 defined($protoype) ? "sub $fullname $protoype;" : "sub $fullname;"
184             }
185              
186       1     sub _package_defined {}
187              
188             1;
189             __END__