File Coverage

blib/lib/Env/Path.pm
Criterion Covered Total %
statement 80 164 48.7
branch 26 70 37.1
condition 4 30 13.3
subroutine 15 24 62.5
pod 16 17 94.1
total 141 305 46.2


line stmt bran cond sub pod time code
1             package Env::Path;
2              
3             $VERSION = '0.19';
4              
5             require 5.004;
6 1     1   612 use strict;
  1         1  
  1         87  
7              
8 1 50   1   5 use constant MSWIN => $^O =~ /MSWin|Windows_NT/i ? 1 : 0;
  1         2  
  1         82  
9              
10 1     1   5 use Config;
  1         5  
  1         3077  
11              
12             my $dsep = $Config::Config{path_sep};
13              
14             sub new {
15 4     4 0 22 my $class = shift;
16 4         6 my $pathvar = shift;
17 4         19 my $pathref = \$ENV{$pathvar};
18 4         9 bless $pathref, $class;
19 4 100       21 $pathref->Assign(@_) if @_;
20 4 100       16 return $pathref if defined wantarray;
21 2         173 eval "\@$pathvar\::ISA = '$class'";
22             }
23              
24             sub import {
25 1     1   8 my $class = shift;
26 1 50       2163 return unless @_;
27 0         0 my @list = @_;
28 0 0       0 @list = keys %ENV if $list[0] eq ':all';
29 0         0 for my $pathvar (@list) {
30 0         0 $class->new($pathvar);
31             }
32             }
33              
34             sub AUTOLOAD {
35 3     3   45 my $class = shift;
36 3         23 (my $pathvar = $Env::Path::AUTOLOAD) =~ s/.*:://;
37 3 50       9 return if $pathvar eq 'DESTROY';
38 3         11 $class->new($pathvar, @_);
39             }
40              
41             sub _class2ref {
42 27     27   31 my $proto = shift;
43 27 100       85 ref $proto ? $proto : \$ENV{$proto};
44             }
45              
46             sub PathSeparator {
47 0     0 1 0 shift;
48 0 0       0 $dsep = shift if @_;
49 0         0 return $dsep;
50             }
51              
52             sub Name {
53 2     2 1 12 my $pathref = _class2ref(shift);
54 2         386 for my $name (keys %ENV) {
55 34 100       198 return $name if $pathref == \$ENV{$name};
56             }
57 0         0 return undef;
58             }
59              
60             sub List {
61 10     10 1 21 my $pathref = _class2ref(shift);
62 10         96 return split /$dsep/, $$pathref;
63             }
64              
65             sub Contains {
66 0     0 1 0 my $pathref = _class2ref(shift);
67 0         0 my $entry = shift;
68 0         0 my @list = $pathref->List;
69 0         0 if (MSWIN) {
70             for ($entry, @list) {
71             $_ = lc($_);
72             s%\\%/%g;
73             }
74             }
75 0         0 my %has = map {$_ => 1} @list;
  0         0  
76 0         0 return $has{$entry};
77             }
78             *Has = \&Contains; # backward compatibility
79              
80             sub Assign {
81 4     4 1 9 my $pathref = _class2ref(shift);
82 4         31 $$pathref = join($dsep, @_);
83 4         6 return $pathref;
84             }
85              
86             sub Prepend {
87 0     0 1 0 my $pathref = _class2ref(shift);
88 0         0 $pathref->Remove(@_);
89 0 0       0 $$pathref = $dsep.$$pathref if $$pathref;
90 0         0 $$pathref = join($dsep, @_) . $$pathref;
91 0         0 return $pathref;
92             }
93              
94             sub Append {
95 2     2 1 5 my $pathref = _class2ref(shift);
96 2         9 $pathref->Remove(@_);
97 2 50       8 $$pathref .= $dsep if $$pathref;
98 2         9 $$pathref .= join($dsep, @_);
99 2         5 return $pathref;
100             }
101              
102             sub InsertBefore {
103 0     0 1 0 my $pathref = _class2ref(shift);
104 0         0 my $marker = shift;
105 0         0 $pathref->Remove(@_);
106 0         0 my $insert = join($dsep, map {split ','} @_);
  0         0  
107 0   0     0 my $temp = $$pathref || '';
108 0         0 $$pathref = '';
109 0         0 for (split /$dsep/, $temp) {
110 0   0     0 $_ ||= '.';
111 0 0       0 $$pathref .= $dsep if $$pathref;
112 0 0 0     0 if ($marker && $_ eq $marker) {
113 0         0 $$pathref .= $insert . $dsep;
114 0         0 undef $marker;
115             }
116 0         0 $$pathref .= $_;
117             }
118 0 0       0 if (defined $marker) {
119 0 0       0 $$pathref = $$pathref ? "$insert$dsep$$pathref" : $insert;
120             }
121 0         0 return $pathref;
122             }
123              
124             sub InsertAfter {
125 0     0 1 0 my $pathref = _class2ref(shift);
126 0         0 my $marker = shift;
127 0         0 $pathref->Remove(@_);
128 0         0 my $insert = join($dsep, map {split ','} @_);
  0         0  
129 0   0     0 my $temp = $$pathref || '';
130 0         0 $$pathref = '';
131 0         0 for (split /$dsep/, $temp) {
132 0   0     0 $_ ||= '.';
133 0 0       0 $$pathref .= $dsep if $$pathref;
134 0         0 $$pathref .= $_;
135 0 0 0     0 if ($marker && $_ eq $marker) {
136 0         0 $$pathref .= $dsep . $insert;
137 0         0 undef $marker;
138             }
139             }
140 0 0       0 if (defined $marker) {
141 0 0       0 $$pathref = $$pathref ? "$$pathref$dsep$insert" : $insert;
142             }
143 0         0 return $pathref;
144             }
145              
146             sub Remove {
147 2     2 1 11 my $pathref = _class2ref(shift);
148 2 50       6 return $pathref unless $$pathref;
149 2         3 my %remove = map {$_ => 1} @_;
  10         33  
150 2         6 if (MSWIN) {
151             for (keys %remove) {
152             (my $lcname = lc($_)) =~ s%\\%/%g;
153             delete $remove{$_};
154             $remove{lc($_)} = 1;
155             }
156             }
157 2 50       15 my @entries = map {$_ || '.'} split(/$dsep/, $$pathref);
  9         30  
158 2         4 if (MSWIN) {
159             my @left = ();
160             for (@entries) {
161             (my $lcname = lc($_)) =~ s%\\%/%g;
162             push(@left, $_) unless $remove{$lcname};
163             }
164             $$pathref = join($dsep, @left);
165             } else {
166 2         4 $$pathref = join($dsep, grep {!$remove{$_}} @entries);
  9         26  
167             }
168 2         7 return $pathref;
169             }
170              
171             sub Replace {
172 1     1 1 7 my $pathref = _class2ref(shift);
173 1 50       4 return $pathref unless $$pathref;
174 1         2 my $re = shift;
175 1         25 my @temp = split /$dsep/, $$pathref;
176 1         4 for (@temp) {
177 7   50     13 $_ ||= '.';
178 7 100       35 if (/$re/) {
179 2         4 $_ = join($dsep, map {split ','} @_);
  4         14  
180             }
181             }
182 1         4 $$pathref = join($dsep, @temp);
183 1         6 return $pathref;
184             }
185              
186             sub ListNonexistent {
187 0     0 1 0 my $pathref = _class2ref(shift);
188 0 0       0 return $pathref unless $$pathref;
189 0         0 my @missing = ();
190 0         0 for (split /$dsep/, $$pathref) {
191 0 0 0     0 push(@missing, $_) if $_ && ! -e $_;
192             }
193 0         0 return @missing;
194             }
195              
196             sub DeleteNonexistent {
197 3     3 1 7 my $pathref = _class2ref(shift);
198 3 50       7 return $pathref unless $$pathref;
199 3         7 my $temp = $$pathref;
200 3         9 $$pathref = '';
201 3         25 for (split /$dsep/, $temp) {
202 22   50     41 $_ ||= '.';
203 22 100       494 next if ! -e $_;
204 12 100       38 $$pathref .= $dsep if $$pathref;
205 12         28 $$pathref .= $_;
206             }
207 3         11 return $pathref;
208             }
209              
210             sub Uniqify {
211 3     3 1 8 my $pathref = _class2ref(shift);
212 3         4 my %seen;
213 3   50     9 my $temp = $$pathref || '';
214 3         9 $$pathref = '';
215 3         23 for (split /$dsep/, $temp) {
216 31   50     86 $_ ||= '.';
217 31         37 my $entry = MSWIN ? lc($_) : $_;
218 31 100       83 next if $seen{$entry}++;
219 22 100       64 $$pathref .= $dsep if $$pathref;
220 22         63 $$pathref .= $_;
221             }
222 3         16 return $pathref;
223             }
224              
225             sub Whence {
226 0     0 1   my $pathref = _class2ref(shift);
227 0           my $pat = shift;
228 0           my(@found, %seen);
229 0           for my $dir (split /$dsep/, $$pathref) {
230 0   0       $dir ||= '.';
231 0           $dir =~ s%[/\\]+$%%;
232 0           $dir =~ s%([/\\])[/\\]+%$1%;
233             # On &^#$ Windows we need to convert paths to use /, then glob
234             # using bsd_glob because it will automatically ignore case,
235             # then convert back to \ iff the original paths preferred it.
236             # Without this some paths, esp UNC paths, get mixed up.
237             # We also have to deal with PATHEXT.
238 0           if (MSWIN) {
239             for my $ext ('', split ';', $ENV{PATHEXT}) {
240             (my $glob = "$dir/$pat$ext") =~ s%\\%/%g;
241             my @matches = File::Glob::bsd_glob($glob);
242             if ($dir eq '.' || $dir =~ m%\\%) {
243             $glob =~ s%/%\\%g;
244             for (@matches) { s%/%\\%g }
245             }
246             push(@found, grep {-f $_ && !$seen{$_}++} $glob, @matches);
247             }
248             } else {
249 0           my $glob = "$dir/$pat";
250 0           my @matches = glob($glob);
251 0 0         if ($^O =~ m%cygwin%i) {
252 0 0         push(@found, grep {-f $_ && !$seen{$_}++} $glob, @matches);
  0            
253             } else {
254 0 0 0       push(@found, grep {-f $_ && -x _ && !$seen{$_}++} $glob, @matches);
  0            
255             }
256             }
257             }
258 0           return @found;
259             }
260              
261             sub Shell {
262 0     0 1   my $pathref = _class2ref(shift);
263 0           my $name = $pathref->Name;
264 0           my $winshell = MSWIN && !$ENV{SHELL};
265 0 0         my $str = "set " if $winshell;
266 0           $str .= qq($name="$$pathref");
267 0 0         $str .= "; export $name" if !$winshell;
268 0           return $str;
269             }
270              
271             # Nothing to do here, just avoiding interaction with AUTOLOAD.
272 0     0     sub DESTROY { }
273              
274             1;
275              
276             __END__