File Coverage

blib/lib/Path/Naive.pm
Criterion Covered Total %
statement 69 69 100.0
branch 46 48 95.8
condition 32 36 88.8
subroutine 13 13 100.0
pod 9 9 100.0
total 169 175 96.5


line stmt bran cond sub pod time code
1             package Path::Naive;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2020-02-12'; # DATE
5             our $DIST = 'Path-Naive'; # DIST
6             our $VERSION = '0.043'; # VERSION
7              
8 1     1   73251 use strict;
  1         10  
  1         30  
9 1     1   5 use warnings;
  1         2  
  1         24  
10              
11 1     1   4 use Exporter;
  1         2  
  1         1038  
12             our @ISA = qw(Exporter);
13             our @EXPORT_OK = qw(
14             abs_path
15             concat_and_normalize_path
16             concat_path
17             normalize_and_split_path
18             normalize_path
19             is_abs_path
20             is_rel_path
21             rel_path
22             split_path
23             );
24              
25             sub abs_path {
26 8     8 1 2664 my ($path, $base) = @_;
27              
28 8 100 100     66 die "Please specify path (first arg)" unless defined $path && length $path;
29 5 50 33     19 die "Please specify base (second arg)" unless defined $base && length $base;
30 5 100       10 die "base must be absolute" unless is_abs_path($base);
31 4         11 concat_and_normalize_path($base, $path);
32             }
33              
34             sub is_abs_path {
35 29     29 1 3589 my $path = shift;
36 29 100 100     119 die "Please specify path" unless defined $path && length $path;
37 26 100       153 $path =~ m!\A/! ? 1:0;
38             }
39              
40             sub is_rel_path {
41 5     5 1 3518 my $path = shift;
42 5 100 100     79 die "Please specify path" unless defined $path && length $path;
43 2 100       13 $path =~ m!\A/! ? 0:1;
44             }
45              
46             sub concat_path {
47 27 100   27 1 3919 die "Please specify at least two paths" unless @_ > 1;
48 21         31 my $i = 0;
49 21         30 my $res = $_[0];
50 21         37 for (@_) {
51 44 50 33     129 die "Please specify path (#$i)" unless defined && length;
52 44 100       78 next unless $i++;
53 23 100       65 if (m!\A/!) {
54 6         13 $res = $_;
55             } else {
56 17 100       68 $res .= ($res =~ m!/\z! ? "" : "/") . $_;
57             }
58             }
59 21         60 $res;
60             }
61              
62             sub concat_and_normalize_path {
63 16     16 1 3574 normalize_path(concat_path(@_));
64             }
65              
66             my $_split;
67             sub _normalize_path {
68 57     57   101 my $path = shift;
69 57         102 my @elems0 = split_path($path);
70 51         132 my $is_abs = $path =~ m!\A/!;
71 51         71 my @elems;
72 51         147 while (@elems0) {
73 121         177 my $elem = shift @elems0;
74 121 100 100     291 next if $elem eq '.' && (@elems || @elems0 || $is_abs);
      100        
75 102 100 100     272 do { pop @elems; next } if $elem eq '..' &&
  13   100     20  
  13         32  
76             (@elems>1 && $elems[-1] ne '..' ||
77             @elems==1 && $elems[-1] ne '..' && $elems[-1] ne '.' && @elems0 ||
78             $is_abs);
79 89         202 push @elems, $elem;
80             }
81 51 100       112 return @elems if $_split;
82 38 100       235 ($is_abs ? "/" : "") . join("/", @elems);
83             }
84              
85             sub normalize_path {
86 41     41 1 3594 $_split = 0;
87 41         123 goto &_normalize_path;
88             }
89              
90             sub normalize_and_split_path {
91 16     16 1 3613 $_split = 1;
92 16         42 goto &_normalize_path;
93             }
94              
95             sub rel_path {
96 13     13 1 5057 my ($path, $base) = @_;
97              
98 13 100 100     81 die "Please specify path (first arg)" unless defined $path && length $path;
99 10 100 100     50 die "Please specify base (second arg)" unless defined $base && length $base;
100 8 100       18 die "path must be absolute" unless is_abs_path($path);
101 7 100       16 die "base must be absolute" unless is_abs_path($base);
102 6         14 my @elems_path = normalize_and_split_path($path);
103 6         13 my @elems_base = normalize_and_split_path($base);
104              
105 6         9 my $num_common_elems = 0;
106 6         17 for (0..$#elems_base) {
107 9 100       19 last unless @elems_path > $num_common_elems;
108             last unless
109 8 100       17 $elems_path[$num_common_elems] eq $elems_base[$num_common_elems];
110 6         10 $num_common_elems++;
111             }
112 6         10 my @elems;
113 6         16 push @elems, ".." for ($num_common_elems .. $#elems_base);
114 6         15 push @elems, @elems_path[$num_common_elems .. $#elems_path];
115 6 100       14 @elems = (".") unless @elems;
116 6         34 join("/", @elems);
117             }
118              
119             sub split_path {
120 70     70 1 3726 my $path = shift;
121 70 100 100     341 die "Please specify path" unless defined $path && length $path;
122 61         519 grep {length} split qr!/+!, $path;
  166         410  
123             }
124              
125             1;
126             # ABSTRACT: Yet another abstract, Unix-like path manipulation routines
127              
128             __END__