File Coverage

blib/lib/Module/Which/P5Path.pm
Criterion Covered Total %
statement 52 63 82.5
branch 13 18 72.2
condition 1 2 50.0
subroutine 12 15 80.0
pod 3 3 100.0
total 81 101 80.2


line stmt bran cond sub pod time code
1              
2             package Module::Which::P5Path;
3             $Module::Which::P5Path::VERSION = '0.04';
4 1     1   847 use 5.006;
  1         4  
  1         44  
5 1     1   6 use strict;
  1         3  
  1         35  
6 1     1   5 use warnings;
  1         2  
  1         73  
7              
8             require Exporter;
9              
10             our @ISA = qw(Exporter);
11             our @EXPORT_OK = qw(path_to_p5path path_to_p5 p5path_to_path);
12              
13 1     1   5 use Config;
  1         1  
  1         894  
14             require File::Spec::Unix; # qw(splitdir catdir);
15             require File::Spec;
16              
17             # NOTE. To map config vars to their values, like this
18             # ('archlib', 'perlpath') => ( $Config{archlib}, $Config{perlpath} )
19             # we only need the expression "@Config{@_}".
20              
21             # my @vars = _purge_vars('a', 'b', 'c')
22             # Purges a list of Config variable names by eliminating those with
23             # false and duplicate values. The original order is preserved.
24             sub _purge_vars {
25 5     5   7 my @vars;
26             my %h;
27 5         49 for my $val (@Config{@_}) {
28 60         183 my $var = shift @_;
29 60 100       318 next unless $val; # skip undefs and ''
30 40 100       10908 unless ($h{$val}++) { # keep only the first occurrence of a value
31 25         63 push @vars, $var;
32             }
33             }
34             return @vars
35 5         83 }
36              
37             sub _is_windows {
38 8     8   189 return $^O =~ /^(MSWin32|cygwin)/i;
39             }
40              
41             sub _is_case_tolerant {
42 0     0   0 return $^O =~ /^(MSWin32|cygwin)/i;
43             }
44             # it would make sense to use File::Spec->case_tolerant
45             # which should return 1 for Windows and Cygwin
46             # but it does not in Cygwin.
47              
48             # tells whether a path lies under a directory path
49             # (it just checks to see if ...
50             #
51             # NOTE. include (?i) in pattern below when case_tolerant
52              
53             # turns 'blib\lib' into 'blib[\\/]lib'
54             # and 'a/b\c' into 'a[\\/]b[\\/]c'
55             sub _win_re {
56 0     0   0 my $p = shift;
57 0 0       0 $p =~ s!([\\/])|(.)! $1?'[\\\\/]':"\Q$2" !ge;
  0         0  
58 0         0 return $p
59             }
60             # is(_win_pattern('blib\lib'), 'blib[\\/]lib');
61             # is(_win_pattern('a/b\c'), 'a[\\/]b[\\/]c');
62             # is(_win_pattern('dir/f.pl'), 'dir[\\/]f\.pl');
63              
64             sub _is_under {
65 8     8   13 my $path = shift;
66 8         11 my $dir = shift;
67 8 50       18 return $path =~ /^\Q$dir\E/ unless _is_windows;
68             # windows is: case tolerant and accepts '\\' or '/'
69 0         0 my $dir_re = _win_re($dir);
70 0         0 return $path =~ /(?i)^$dir_re/
71             }
72              
73             sub _parent {
74 0     0   0 my $path = shift;
75 0         0 my @path = File::Spec::Unix->splitdir($path);
76 0         0 pop @path;
77 0         0 return File::Spec::Unix->catdir(@path)
78             }
79              
80             # this computes a relative path from an absolute WHEN
81             # we know that the base is a descendant of the path
82             # (so we don't need to handle '.', '..' and the like)
83             # like File::Spec->abs2rel() is able to do
84             sub _abs2rel {
85 3     3   6 my $path = shift;
86 3         6 my $base = shift;
87 3         30 my @path = File::Spec::Unix->splitdir($path);
88 3         14 my $base_nodes = File::Spec::Unix->splitdir($base);
89 3         10 splice @path, 0, $base_nodes;
90 3         25 return File::Spec::Unix->catdir(@path);
91             }
92              
93             # my ($p5path, $p5base) = _resolve_path($path, @ivars);
94             # my $p5path = _resolve_path($path, @ivars);
95             sub _resolve_path {
96 5     5   9 my $path = shift;
97 5 100       12 unless ($path) {
98 1 50       4 return ($path, '') if wantarray;
99 1         5 return $path
100             }
101              
102 4         13 my @vars = @_;
103 4         11 for (@vars) {
104 8         53 my $p5p = $Config{$_};
105 8 100       28 if (_is_under($path, $p5p)) {
106 3         9 my $p5base = '${' . $_ . '}/';
107             #my $p5path = $p5base . File::Spec::Unix->abs2rel($path, $Config{$_});
108 3         9 my $p5path = $p5base . _abs2rel($path, $p5p);
109 3 100       12 return ($p5path, $p5base) if wantarray;
110 2         38 return $p5path
111             }
112             }
113 1 50       4 return ($path, _parent($path)) if wantarray; # !FIXME: I don't like this!
114 1         10 return $path # no resolution against given vars
115             }
116              
117             our @DEFAULT_IVARS = qw(
118             installarchlib archlib installprivlib privlib
119             installsitearch installsitelib sitelib sitelib_stem
120             installvendorarch installvendorlib vendorlib vendorlib_stem
121             );
122              
123             # ($p5path, $p5base) = path_to_p5($path)
124             # $p5path = path_to_p5($path, include => \@IVARS)
125             sub path_to_p5 {
126 5     5 1 1170 my $path = shift;
127 5         14 my %options = @_;
128 5   50     378 my $ivars = $options{install_vars} || \@DEFAULT_IVARS;
129 5         14 my @ivars = _purge_vars(@$ivars);
130 5         17 return _resolve_path($path, @ivars);
131             }
132              
133             # $p5path = path_to_p5path($path);
134             # $p5path = path_to_p5path($path, include => \@IVARS);
135             sub path_to_p5path {
136 3     3 1 4179 return scalar path_to_p5(@_);
137             }
138              
139             sub p5path_to_path {
140 3     3 1 6 my $path = shift;
141 3         17 $path =~ s/^\$\{(\w+)\}/$Config{$1}/;
142 3         18 return $path
143              
144             }
145              
146             1;
147              
148             __END__