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 2     2   464228 use strict;
  2         5  
  2         112  
4 2     2   20 use warnings;
  2         4  
  2         170  
5              
6 2     2   14 use Exporter qw(import);
  2         4  
  2         2463  
7              
8             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
9             our $DATE = '2024-07-17'; # DATE
10             our $DIST = 'Path-Naive'; # DIST
11             our $VERSION = '0.044'; # VERSION
12              
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 333638 my ($path, $base) = @_;
27              
28 8 100 100     49 die "Please specify path (first arg)" unless defined $path && length $path;
29 5 50 33     15 die "Please specify base (second arg)" unless defined $base && length $base;
30 5 100       9 die "base must be absolute" unless is_abs_path($base);
31 4         8 concat_and_normalize_path($base, $path);
32             }
33              
34             sub is_abs_path {
35 29     29 1 3875 my $path = shift;
36 29 100 100     90 die "Please specify path" unless defined $path && length $path;
37 26 100       133 $path =~ m!\A/! ? 1:0;
38             }
39              
40             sub is_rel_path {
41 5     5 1 3671 my $path = shift;
42 5 100 100     35 die "Please specify path" unless defined $path && length $path;
43 2 100       12 $path =~ m!\A/! ? 0:1;
44             }
45              
46             sub concat_path {
47 27 100   27 1 8077 die "Please specify at least two paths" unless @_ > 1;
48 21         45 my $i = 0;
49 21         22 my $res = $_[0];
50 21         28 for (@_) {
51 44 50 33     104 die "Please specify path (#$i)" unless defined && length;
52 44 100       78 next unless $i++;
53 23 100       55 if (m!\A/!) {
54 6         8 $res = $_;
55             } else {
56 17 100       46 $res .= ($res =~ m!/\z! ? "" : "/") . $_;
57             }
58             }
59 21         53 $res;
60             }
61              
62             sub concat_and_normalize_path {
63 16     16 1 4773 normalize_path(concat_path(@_));
64             }
65              
66             my $_split;
67             sub _normalize_path {
68 57     57   62 my $path = shift;
69 57         115 my @elems0 = split_path($path);
70 51         117 my $is_abs = $path =~ m!\A/!;
71 51         51 my @elems;
72 51         81 while (@elems0) {
73 121         107 my $elem = shift @elems0;
74 121 100 100     234 next if $elem eq '.' && (@elems || @elems0 || $is_abs);
      100        
75 102 100 100     233 do { pop @elems; next } if $elem eq '..' &&
  13   100     15  
  13         29  
76             (@elems>1 && $elems[-1] ne '..' ||
77             @elems==1 && $elems[-1] ne '..' && $elems[-1] ne '.' && @elems0 ||
78             $is_abs);
79 89         138 push @elems, $elem;
80             }
81 51 100       113 return @elems if $_split;
82 38 100       216 ($is_abs ? "/" : "") . join("/", @elems);
83             }
84              
85             sub normalize_path {
86 41     41 1 3577 $_split = 0;
87 41         98 goto &_normalize_path;
88             }
89              
90             sub normalize_and_split_path {
91 16     16 1 5516 $_split = 1;
92 16         34 goto &_normalize_path;
93             }
94              
95             sub rel_path {
96 13     13 1 4548 my ($path, $base) = @_;
97              
98 13 100 100     62 die "Please specify path (first arg)" unless defined $path && length $path;
99 10 100 100     38 die "Please specify base (second arg)" unless defined $base && length $base;
100 8 100       15 die "path must be absolute" unless is_abs_path($path);
101 7 100       8 die "base must be absolute" unless is_abs_path($base);
102 6         12 my @elems_path = normalize_and_split_path($path);
103 6         9 my @elems_base = normalize_and_split_path($base);
104              
105 6         7 my $num_common_elems = 0;
106 6         14 for (0..$#elems_base) {
107 9 100       15 last unless @elems_path > $num_common_elems;
108             last unless
109 8 100       16 $elems_path[$num_common_elems] eq $elems_base[$num_common_elems];
110 6         7 $num_common_elems++;
111             }
112 6         8 my @elems;
113 6         12 push @elems, ".." for ($num_common_elems .. $#elems_base);
114 6         14 push @elems, @elems_path[$num_common_elems .. $#elems_path];
115 6 100       10 @elems = (".") unless @elems;
116 6         28 join("/", @elems);
117             }
118              
119             sub split_path {
120 70     70 1 3959 my $path = shift;
121 70 100 100     279 die "Please specify path" unless defined $path && length $path;
122 61         573 grep {length} split qr!/+!, $path;
  166         342  
123             }
124              
125             1;
126             # ABSTRACT: Yet another abstract, Unix-like path manipulation routines
127              
128             __END__