File Coverage

blib/lib/Module/Which/P5Path.pm
Criterion Covered Total %
statement 51 62 82.2
branch 13 18 72.2
condition 1 2 50.0
subroutine 12 15 80.0
pod 3 3 100.0
total 80 100 80.0


line stmt bran cond sub pod time code
1              
2             package Module::Which::P5Path;
3             $Module::Which::P5Path::VERSION = '0.05';
4 1     1   796 use 5.006;
  1         3  
5 1     1   4 use strict;
  1         2  
  1         22  
6 1     1   5 use warnings;
  1         1  
  1         66  
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         2  
  1         948  
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   6 my @vars;
26             my %h;
27 5         51 for my $val (@Config{@_}) {
28 60         78 my $var = shift @_;
29 60 100       596 next unless $val; # skip undefs and ''
30 40 100       117 unless ($h{$val}++) { # keep only the first occurrence of a value
31 25         45 push @vars, $var;
32             }
33             }
34             return @vars
35 5         37 }
36              
37             sub _is_windows {
38 8     8   112 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   8 my $path = shift;
66 8         11 my $dir = shift;
67 8 50       13 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   4 my $path = shift;
86 3         4 my $base = shift;
87 3         22 my @path = File::Spec::Unix->splitdir($path);
88 3         10 my $base_nodes = File::Spec::Unix->splitdir($base);
89 3         7 splice @path, 0, $base_nodes;
90 3         18 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   8 my $path = shift;
97 5 100       12 unless ($path) {
98 1 50       5 return ($path, '') if wantarray;
99 1         5 return $path
100             }
101              
102 4         7 my @vars = @_;
103 4         7 for (@vars) {
104 8         39 my $p5p = $Config{$_};
105 8 100       18 if (_is_under($path, $p5p)) {
106 3         7 my $p5base = '${' . $_ . '}/';
107             #my $p5path = $p5base . File::Spec::Unix->abs2rel($path, $Config{$_});
108 3         6 my $p5path = $p5base . _abs2rel($path, $p5p);
109 3 100       10 return ($p5path, $p5base) if wantarray;
110 2         12 return $p5path
111             }
112             }
113 1 50       3 return ($path, _parent($path)) if wantarray; # !FIXME: I don't like this!
114 1         6 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 684 my $path = shift;
127 5         7 my %options = @_;
128 5   50     27 my $ivars = $options{install_vars} || \@DEFAULT_IVARS;
129 5         11 my @ivars = _purge_vars(@$ivars);
130 5         11 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 492 return scalar path_to_p5(@_);
137             }
138              
139             sub p5path_to_path {
140 3     3 1 5 my $path = shift;
141 3         16 $path =~ s/^\$\{(\w+)\}/$Config{$1}/;
142 3         21 return $path
143              
144             }
145              
146             1;
147              
148             __END__