File: Parents.pm

package info (click to toggle)
libfindbin-libs-perl 4.0.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 704 kB
  • sloc: perl: 1,323; sh: 38; makefile: 7
file content (176 lines) | stat: -rw-r--r-- 3,992 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
########################################################################
# housekeeping
########################################################################
package FindBin::Parents  v0.1.0;
use v5.40;
use parent qw( Exporter );

use Carp            qw( croak   );
use List::Util      qw( reduce  );
use Storable        qw( dclone  );

use File::Spec::Functions
qw
(
    splitpath
    splitdir
    catdir
    catpath
    rel2abs
    canonpath
);

########################################################################
# package variables and sanity checks 
########################################################################

our @EXPORT_OK  
= qw
(
    dir_paths
    clear_parent_cache
);

my %path2dirz   = ();

########################################################################
# utility subs
########################################################################

########################################################################
# exported
########################################################################

# avoid issues with repeated use on different paths.

sub clear_parent_cache()
{
    %path2dirz  = ();
}

sub dir_paths( $path, $assume_dir = 1 )
{
    $path
    or croak 'Bogus dir_paths: false path argument.';

    my $dirz
    = $path2dirz{ $path . $; . $assume_dir }
    ||= do
    {
        # treat non-existant paths as dir's, mainly for testing.

        my $is_dir  = $assume_dir || -d $path;

        my ( $vol, $dir ) = splitpath $path, $is_dir;

        # ditch the starting directory.

        my @dirz    = splitdir rel2abs canonpath $dir;

        # fix for File::Spec::VMS missing the leading empty
        # string on a split. this can be removed once File::Spec
        # is fixed -- which appears to be never.

        my $tmp
        = $dirz[0]
        ? ''
        : shift @dirz
        ;

        [
            reverse
            map
            {
                catpath $vol => $_, ''
            }
            map
            {
                $tmp    = catdir $tmp, $_
            }
            ( '' => @dirz )
        ]
    };

    wantarray
    ?   @$dirz
    : [ @$dirz ]
}

1
__END__

=head1 NAME

FindBin::Parents - List parent dirs of the given path from curr to root.

=head1 SYNOPSIS

    use FindBin::Parents qw( dir_paths );

    # on *NIX (incl. OSX)
    # '/foo/bar/bim/bam' yields
    # /foo/bar/bim/bam
    # /foo/bar/bim
    # /foo/bar
    # /foo
    #
    # on VMS
    # 'Bletch$Blort:[foo.bar.bim.bam]' yields
    # Bletch$Blort:[foo.bar.bim.bam] 
    # Bletch$Blort:[foo.bar.bim] 
    # Bletch$Blort:[foo.bar] 
    # Bletch$Blort:[foo] 
    #
    # on MSW
    # 'z:/foo/bar/bim/bam' yields
    # z:/foo/bar/bim/bam
    # z:/foo/bar/bim 
    # z:/foo/bar 
    # z:/foo 
    #
    # $path is first passed through rel2abs and canonpath 
    # which should yield clean, absolute paths. 
    #
    # note that the return vlaue is context-sensitive:

    my $array_ref   = dir_paths $path;
    my @array       = dir_paths $path;

    # for any non-directory /foo/bar/bletch/blort, the final
    # 'blort' is dropped and the paths leading to it are returned:

    dir_paths $0;

    # /foo/bar/bletch   # parent dir of blort
    # /foo/bar
    # /foo

    # Note: non-existant paths are processed, but may require
    # an extra assume-dir argument to treat the argument as a 
    # directory (or not, no way to tell unless it exists, eh?).
    #
    # the default is true, these are equivalent:

    my @found       
    = dir_paths '/foo/bar/bletch/blort/non-existent';

    my @found       
    = dir_paths '/foo/bar/bletch/blort/non-existent', 1;

    # /foo/bar/bletch/blort/non-existant
    # /foo/bar/bletch/blort
    # /foo/bar/bletch
    # /foo/bar/bletch
    # /foo/bar
    # /foo

    # false value drops the last entry:

    my @found       
    = dir_paths '/foo/bar/bletch/blort/non-existant', 0;

    # /foo/bar/bletch/blort
    # /foo/bar/bletch
    # /foo/bar/bletch
    # /foo/bar
    # /foo