File Coverage

blib/lib/File/AddInc.pm
Criterion Covered Total %
statement 98 120 81.6
branch 16 28 57.1
condition 5 9 55.5
subroutine 24 27 88.8
pod 2 13 15.3
total 145 197 73.6


line stmt bran cond sub pod time code
1             package File::AddInc;
2 8     8   369448 use 5.008001;
  8         32  
3 8     8   55 use strict;
  8         23  
  8         234  
4 8     8   40 use warnings;
  8         12  
  8         475  
5 8     8   3451 use mro qw/c3/;
  8         5109  
  8         81  
6              
7             our $VERSION = "0.003";
8              
9 8     8   533 use File::Spec;
  8         15  
  8         249  
10 8     8   39 use File::Basename;
  8         14  
  8         886  
11 8     8   48 use Cwd ();
  8         13  
  8         143  
12 8     8   3897 use lib ();
  8         6439  
  8         206  
13 8     8   50 use Carp ();
  8         15  
  8         287  
14              
15 8     8   41 use constant DEBUG => $ENV{DEBUG_MOP4IMPORT};
  8         13  
  8         1011  
16              
17             {
18             package
19             File::AddInc::Opts;
20 8     8   4122 use fields qw/caller callpack filename line stash/;
  8         14315  
  8         41  
21              
22             # This Opts->new does not bless the hash.
23             sub new {
24 6     6   140 my ($pack, %opts) = @_;
25 6         34 my __PACKAGE__ $opts = \%opts;
26             ($opts->{callpack}, $opts->{filename}, $opts->{line})
27 6         44 = @{$opts->{caller}};
  6         26  
28 6         21 $opts;
29             }
30             }
31             sub Opts () {'File::AddInc::Opts'}
32              
33             #
34             # Limited version of MOP4Import::Declare#import()
35             #
36             sub import {
37 5     5   63 my ($pack, @pragma) = @_;
38              
39 5         35 my Opts $opts = $pack->Opts->new(caller => [caller]);
40              
41 5         20 $pack->dispatch_declare($opts, $pack->always_exports, @pragma);
42             }
43              
44             sub always_exports {
45 5     5 0 19 (-file_inc)
46             }
47              
48             sub dispatch_declare {
49 5     5 0 17 (my $pack, my Opts $opts, my @pragma) = @_;
50              
51 5         13 foreach my $pragmaSpec (@pragma) {
52              
53 9         567 my ($pragma, @args) = do {
54 9 100 66     100 if (ref $pragmaSpec eq 'ARRAY') {
    100 33        
    50          
55 2         6 @$pragmaSpec
56             }
57             elsif (not ref $pragmaSpec and $pragmaSpec =~ /^-(\w+)$/) {
58 6         27 $1
59             }
60             elsif (not ref $pragmaSpec and $pragmaSpec =~ /^\$\w+\z/) {
61 1         4 (libdir_var => $pragmaSpec)
62             }
63             else {
64 0         0 Carp::croak "Unsupported pragma: $pragmaSpec";
65             }
66             };
67              
68 9 50       111 my $sub = $pack->can("declare_$pragma")
69             or Carp::croak "Unknown pragma: $pragma";
70              
71 9         27 $sub->($pack, $opts, @args);
72             }
73             }
74              
75             sub get_libdir {
76 10     10 0 20 (my $pack, my Opts $opts) = @_;
77             $opts->{stash}{$pack}{libdir}
78 10   66     53 //= libdir($pack, $opts->{callpack}, $opts->{filename});
79             }
80              
81             sub declare_file_inc {
82 5     5 0 12 (my $pack, my Opts $opts) = @_;
83              
84 5         14 my $libdir = $pack->get_libdir($opts);
85              
86 5         18 $pack->add_inc_if_necessary($libdir);
87             }
88              
89             sub declare_local_lib {
90 1     1 0 2 (my $pack, my Opts $opts) = @_;
91              
92 1         5 $pack->declare_these_libdirs($opts, '', [dirname => "local/lib/perl5"]);
93             }
94              
95             sub add_inc_if_necessary {
96 8     8 1 21 my ($pack, @libdir) = @_;
97              
98 8 50       17 if (my @necessary = grep {
99              
100 13         21 my $dir = $_;
101 13 50       214 -d $dir and not grep {$dir eq $_} @INC;
  115         202  
102              
103             } @libdir) {
104              
105 8         13 print STDERR "# use lib ", join(", ", map(qq{'$_'}, @necessary))
106             , "\n" if DEBUG;
107              
108 8         58 lib->import(@necessary);
109              
110             } else {
111              
112 0         0 print STDERR "# No need to add libs: ", join(", ", map(qq{'$_'}, @libdir))
113             , "\n" if DEBUG;
114             }
115             }
116              
117             sub declare_libdir_var {
118 2     2 0 6 (my $pack, my Opts $opts, my $varname) = @_;
119              
120 2         6 my $libdir = $pack->get_libdir($opts);
121              
122 2         9 $varname =~ s/^\$//;
123              
124 2         8 my $fullvarname = join("::", $opts->{callpack}, $varname);
125              
126 8     8   8073 my $glob = do {no strict qw/refs/; \*{$fullvarname}};
  8         20  
  8         7170  
  2         4  
  2         4  
  2         13  
127              
128 2         4 print STDERR "# set \$$fullvarname = '$libdir'\n" if DEBUG;
129              
130 2         194 *$glob = \$libdir;
131             }
132              
133             sub declare_these_libdirs {
134 3     3 0 11 (my $pack, my Opts $opts, my @dirSpec) = @_;
135              
136 3         10 my $libdir = $pack->get_libdir($opts);
137              
138             my @libdir = map {
139 3 100       6 if (ref $_) {
  8         17  
140              
141 1         4 my ($kind, @rest) = @$_;
142              
143 1 50       7 my $sub = $pack->can("libdir_to_$kind")
144             or Carp::croak "Unknown libdir spec: $kind";
145              
146 1         4 my $realPrefix = $sub->($pack, $libdir);
147              
148 1         22 File::Spec->catfile($realPrefix, map {split(m{/}, $_)} @rest);
  1         27  
149              
150             }
151             # elsif (/\%s/) {
152             # File::Spec->catfile(split m{/}, sprintf($_, $libdir));
153             # }
154             else {
155              
156 7         77 File::Spec->catfile($libdir, split(m{/}, $_));
157             }
158             } @dirSpec;
159              
160 3         10 add_inc_if_necessary($pack, @libdir);
161             }
162              
163             sub libdir_to_libdir {
164 0     0 0 0 my ($pack, $libdir) = @_;
165 0         0 $libdir;
166             }
167              
168             sub libdir_to_dirname {
169 1     1 0 2 my ($pack, $libdir) = @_;
170 1         88 dirname($libdir);
171             }
172              
173             sub libdir {
174 9     9 1 536250 my ($pack, @caller) = @_;
175              
176 9 100       36 my ($callpack, $filename) = @caller ? @caller : caller;
177              
178 9         40 (my $packfn = $callpack) =~ s,::,/,g;
179 9         21 $packfn .= ".pm";
180              
181 9 50       371 my $realFn = -l $filename
182             ? resolve_symlink($pack, $filename)
183             : $filename;
184              
185 9 50       61 if ($^O eq 'MSWin32') {
186 0         0 $packfn =~ s#/#\\#g;
187             }
188              
189 9         219 my $absfn = File::Spec->rel2abs($realFn);
190              
191 9 50       193 $absfn =~ /\Q$packfn\E\z/
192             or Carp::croak("Can't handle this case! absfn=$absfn; packfn=$packfn");
193              
194 9         103 substr($absfn, 0, length($absfn) - length($packfn) - 1);
195             }
196              
197             sub resolve_symlink {
198 0     0 0   my ($pack, $filePath) = @_;
199              
200 0           print STDERR "# resolve_symlink($filePath)...\n" if DEBUG;
201              
202 0           (undef, my ($realDir)) = fileparse($filePath);
203              
204 0           while (defined (my $linkText = readlink $filePath)) {
205 0           ($filePath, $realDir) = resolve_symlink_1($pack, $linkText, $realDir);
206 0           print STDERR "# => $filePath (realDir=$realDir)\n" if DEBUG;
207             }
208              
209 0           return $filePath;
210             }
211              
212             sub resolve_symlink_1 {
213 0     0 0   my ($pack, $linkText, $realDir) = @_;
214              
215 0           my $filePath = do {
216 0 0         if (File::Spec->file_name_is_absolute($linkText)) {
217 0           $linkText;
218             } else {
219 0           File::Spec->catfile($realDir, $linkText);
220             }
221             };
222              
223 0 0         if (wantarray) {
224             # purify x/../y to y
225 0           my $realPath = Cwd::realpath($filePath);
226 0           (undef, $realDir) = fileparse($realPath);
227 0           ($realPath, $realDir);
228             } else {
229 0           $filePath;
230             }
231             }
232              
233             1;