| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#======================================================================== |
|
2
|
|
|
|
|
|
|
# |
|
3
|
|
|
|
|
|
|
# Badger::Filesystem::Path |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# DESCRIPTION |
|
6
|
|
|
|
|
|
|
# OO representation of a path in a filesystem, serving as a base class |
|
7
|
|
|
|
|
|
|
# for file and directories. |
|
8
|
|
|
|
|
|
|
# |
|
9
|
|
|
|
|
|
|
# AUTHOR |
|
10
|
|
|
|
|
|
|
# Andy Wardley |
|
11
|
|
|
|
|
|
|
# |
|
12
|
|
|
|
|
|
|
#======================================================================== |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
package Badger::Filesystem::Path; |
|
15
|
|
|
|
|
|
|
|
|
16
|
70
|
|
|
70
|
|
460
|
use File::Spec; |
|
|
70
|
|
|
|
|
135
|
|
|
|
70
|
|
|
|
|
5335
|
|
|
17
|
|
|
|
|
|
|
use Badger::Class |
|
18
|
70
|
|
|
|
|
1074
|
version => 0.01, |
|
19
|
|
|
|
|
|
|
debug => 0, |
|
20
|
|
|
|
|
|
|
base => 'Badger::Filesystem::Base Badger::Exporter', |
|
21
|
|
|
|
|
|
|
import => 'class', |
|
22
|
|
|
|
|
|
|
constants => 'HASH ARRAY TRUE', |
|
23
|
|
|
|
|
|
|
get_methods => 'path name volume directory', |
|
24
|
|
|
|
|
|
|
utils => 'blessed', |
|
25
|
|
|
|
|
|
|
as_text => 'path', |
|
26
|
|
|
|
|
|
|
is_true => 1, |
|
27
|
|
|
|
|
|
|
constant => { |
|
28
|
|
|
|
|
|
|
type => 'Path', |
|
29
|
|
|
|
|
|
|
STAT_PATH => 17, # offset in extended stat fields |
|
30
|
|
|
|
|
|
|
}, |
|
31
|
|
|
|
|
|
|
exports => { |
|
32
|
|
|
|
|
|
|
tags => { fields => '@STAT_FIELDS' }, |
|
33
|
|
|
|
|
|
|
}, |
|
34
|
|
|
|
|
|
|
messages => { |
|
35
|
|
|
|
|
|
|
no_exist => '%s does not exist: %s', |
|
36
|
|
|
|
|
|
|
bad_stat => '%s cannot be scanned: %s', |
|
37
|
|
|
|
|
|
|
bad_look => 'No path specified to look %s', |
|
38
|
|
|
|
|
|
|
missing => 'No %s specified', |
|
39
|
70
|
|
|
70
|
|
480
|
}; |
|
|
70
|
|
|
|
|
196
|
|
|
40
|
|
|
|
|
|
|
|
|
41
|
70
|
|
|
70
|
|
38481
|
use Badger::Timestamp; |
|
|
70
|
|
|
|
|
195
|
|
|
|
70
|
|
|
|
|
779
|
|
|
42
|
70
|
|
|
70
|
|
1030
|
use Badger::Filesystem; |
|
|
70
|
|
|
|
|
164
|
|
|
|
70
|
|
|
|
|
735
|
|
|
43
|
70
|
|
|
70
|
|
32199
|
use Badger::Filesystem::Directory; |
|
|
70
|
|
|
|
|
167
|
|
|
|
70
|
|
|
|
|
839
|
|
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
our $FILESYSTEM = 'Badger::Filesystem'; |
|
47
|
|
|
|
|
|
|
our $TIMESTAMP = 'Badger::Timestamp'; |
|
48
|
|
|
|
|
|
|
our $MATCH_EXT = qr/\.([^\.]+)$/; # TODO: is this filesystem-specific? |
|
49
|
|
|
|
|
|
|
our @VDN_FIELDS = @Badger::Filesystem::Base::VDN_FIELDS; |
|
50
|
|
|
|
|
|
|
our @STAT_FIELDS = qw( device inode mode links user group device_type |
|
51
|
|
|
|
|
|
|
size atime mtime ctime block_size blocks |
|
52
|
|
|
|
|
|
|
readable writeable executable owner ); |
|
53
|
|
|
|
|
|
|
our $STAT_FIELD = { |
|
54
|
|
|
|
|
|
|
# In here we'll store the map from stat field name to number |
|
55
|
|
|
|
|
|
|
# device => 0, |
|
56
|
|
|
|
|
|
|
# inode => 1, |
|
57
|
|
|
|
|
|
|
# ...etc... |
|
58
|
|
|
|
|
|
|
}; |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
our $TS_FIELD = { |
|
61
|
|
|
|
|
|
|
# On the left we have the timestamp methods we want to generate as |
|
62
|
|
|
|
|
|
|
# wrappers around the stat fields listed on the right. |
|
63
|
|
|
|
|
|
|
created => 'ctime', |
|
64
|
|
|
|
|
|
|
accessed => 'atime', |
|
65
|
|
|
|
|
|
|
modified => 'mtime', |
|
66
|
|
|
|
|
|
|
}; |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# generate methods to access stat fields: mode(), atime(), ctime(), etc. |
|
69
|
|
|
|
|
|
|
my $n = 0; |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
class->methods( |
|
72
|
|
|
|
|
|
|
map { |
|
73
|
|
|
|
|
|
|
my $m = $n++; # new lexical variable for closure |
|
74
|
|
|
|
|
|
|
$STAT_FIELD->{ $_ } = $m; # fill in $STAT_FIELD entry |
|
75
|
56
|
|
|
56
|
|
359
|
$_ => sub { $_[0]->stats->[$m] } # generate subroutine |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
@STAT_FIELDS |
|
78
|
|
|
|
|
|
|
); |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# generate accessed(), created() and modified() methods which return |
|
81
|
|
|
|
|
|
|
# Badger::Timestamp objects for the atime, ctime and mtime stat values |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
class->methods( |
|
84
|
|
|
|
|
|
|
map { |
|
85
|
|
|
|
|
|
|
my $method = $_; # new lexical variable for closure |
|
86
|
|
|
|
|
|
|
my $stat = $TS_FIELD->{ $_ }; |
|
87
|
|
|
|
|
|
|
my $statno = $STAT_FIELD->{ $stat }; |
|
88
|
|
|
|
|
|
|
$method => sub { |
|
89
|
3
|
|
33
|
3
|
|
30
|
return $_[0]->{ $method } |
|
90
|
|
|
|
|
|
|
||= $TIMESTAMP->new( $_[0]->stats->[$statno] ) |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
keys %$TS_FIELD |
|
94
|
|
|
|
|
|
|
); |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# define some aliases |
|
98
|
|
|
|
|
|
|
*is_dir = \&is_directory; |
|
99
|
|
|
|
|
|
|
*dir = \&directory; |
|
100
|
|
|
|
|
|
|
*vol = \&volume; # goes up to 11 |
|
101
|
|
|
|
|
|
|
*ext = \&extension; |
|
102
|
|
|
|
|
|
|
*base_name = \&basename; |
|
103
|
|
|
|
|
|
|
*up = \&parent; |
|
104
|
|
|
|
|
|
|
*meta = \&metadata; |
|
105
|
|
|
|
|
|
|
*canonical = \&absolute; |
|
106
|
|
|
|
|
|
|
*perms = \&permissions; |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub new { |
|
110
|
571
|
|
66
|
571
|
1
|
847
|
my $class = shift; $class = ref $class || $class; |
|
|
571
|
|
|
|
|
1499
|
|
|
111
|
571
|
|
|
|
|
649
|
my $args; |
|
112
|
|
|
|
|
|
|
|
|
113
|
571
|
100
|
|
|
|
978
|
if (@_ == 1) { |
|
114
|
564
|
50
|
66
|
|
|
1132
|
$args = ref $_[0] eq HASH ? shift |
|
|
|
100
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
: ref $_[0] eq ARRAY || ! ref $_[0] ? { path => shift } |
|
116
|
|
|
|
|
|
|
: return $class->error_msg( unexpected => arguments => $_[0] => 'hash ref' ) |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
else { |
|
119
|
7
|
|
|
|
|
18
|
$args = { @_ }; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# allow short aliases for various configuration options, including |
|
123
|
|
|
|
|
|
|
# those of directory/file subclasses to make life easy for them. |
|
124
|
571
|
50
|
0
|
|
|
1083
|
$args->{ filesystem } ||= $args->{ fs } if $args->{ fs }; |
|
125
|
571
|
100
|
33
|
|
|
929
|
$args->{ directory } ||= $args->{ dir } if $args->{ dir }; |
|
126
|
571
|
50
|
0
|
|
|
925
|
$args->{ volume } ||= $args->{ vol } if $args->{ vol }; |
|
127
|
571
|
|
|
|
|
965
|
my $self = bless { }, $class; |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# maintain a reference to the filesystem that created us, if available, |
|
130
|
|
|
|
|
|
|
# but don't bother if we didn't get one - we can use the default |
|
131
|
571
|
100
|
|
|
|
3437
|
$self->{ filesystem } = $args->{ filesystem } if $args->{ filesystem }; |
|
132
|
571
|
|
|
|
|
1399
|
$self->init($args); |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub init { |
|
136
|
33
|
|
|
33
|
1
|
53
|
my ($self, $config) = @_; |
|
137
|
33
|
|
50
|
|
|
62
|
my $path = $config->{ path } || return $self->error_msg( missing => 'path' ); |
|
138
|
33
|
|
|
|
|
62
|
my $fs = $self->filesystem; |
|
139
|
33
|
|
|
|
|
75
|
$path = $self->{ path } = $fs->join_directory($path); |
|
140
|
33
|
|
|
|
|
190
|
return $self; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub is_absolute { |
|
144
|
29
|
|
|
29
|
1
|
63
|
my $self = shift; |
|
145
|
|
|
|
|
|
|
$self->{ absolute } = $self->filesystem->is_absolute($self->{ path }) |
|
146
|
29
|
100
|
|
|
|
107
|
unless defined $self->{ absolute }; |
|
147
|
29
|
|
|
|
|
174
|
return $self->{ absolute }; |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub is_relative { |
|
151
|
2
|
100
|
|
2
|
1
|
11
|
shift->is_absolute ? 0 : 1; |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
sub is_file { |
|
155
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
156
|
0
|
|
0
|
|
|
0
|
my $defn = $self->filesystem->definitive_read($self->{ path }) || return; |
|
157
|
0
|
|
|
|
|
0
|
return -f $defn; |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub is_directory { |
|
161
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
162
|
0
|
|
0
|
|
|
0
|
my $defn = $self->filesystem->definitive_read($self->{ path }) || return; |
|
163
|
0
|
|
|
|
|
0
|
return -d $defn; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
sub absolute { |
|
167
|
21
|
|
|
21
|
1
|
83
|
my $self = shift; |
|
168
|
|
|
|
|
|
|
return $self->is_absolute |
|
169
|
|
|
|
|
|
|
? $self->{ path } |
|
170
|
21
|
100
|
|
|
|
79
|
: $self->filesystem->absolute($self->{ path }); |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub relative { |
|
174
|
81
|
|
|
81
|
1
|
163
|
my $self = shift; |
|
175
|
81
|
|
|
|
|
182
|
my $fs = $self->filesystem; |
|
176
|
81
|
|
|
|
|
256
|
my $path = $fs->join_directory(@_); |
|
177
|
|
|
|
|
|
|
# If the path isn't already absolute then we merge it onto our |
|
178
|
|
|
|
|
|
|
# directory or path if directory is undefined. By calling the |
|
179
|
|
|
|
|
|
|
# base() method, we allow the file subclass to return its |
|
180
|
|
|
|
|
|
|
# parent directory so that things Just Work[tm] |
|
181
|
|
|
|
|
|
|
# $self->debug("relative path: $path is_absolute?\n"); |
|
182
|
81
|
100
|
|
|
|
218
|
return $fs->is_absolute($path) |
|
183
|
|
|
|
|
|
|
? $path |
|
184
|
|
|
|
|
|
|
: $fs->collapse_directory( $fs->join_directory($self->base, $path) ); |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub definitive { |
|
188
|
4
|
|
|
4
|
1
|
17
|
my $self = shift; |
|
189
|
|
|
|
|
|
|
# use the definitive path from the last stat or fetch anew |
|
190
|
|
|
|
|
|
|
return |
|
191
|
|
|
|
|
|
|
($self->{ stats } && $self->{ stats }->[STAT_PATH]) |
|
192
|
4
|
|
33
|
|
|
40
|
|| $self->filesystem->definitive($self->{ path }); |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub collapse { |
|
196
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
197
|
0
|
|
|
|
|
0
|
my $fs = $self->filesystem; |
|
198
|
0
|
|
|
|
|
0
|
$self->{ directory } = $fs->collapse_directory( $self->{ directory } ); |
|
199
|
0
|
|
|
|
|
0
|
$self->{ path } = $fs->join_path( @$self{ @VDN_FIELDS } ); |
|
200
|
0
|
|
|
|
|
0
|
return $self; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub above { |
|
204
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
205
|
0
|
|
|
|
|
0
|
my $this = quotemeta $self->collapse->path; |
|
206
|
0
|
|
0
|
|
|
0
|
my $that = shift || return $self->error_msg( bad_look => 'above' ); |
|
207
|
0
|
0
|
0
|
|
|
0
|
$that = $self->new("$that") unless blessed $that && $that->isa(__PACKAGE__); |
|
208
|
0
|
|
|
|
|
0
|
$that = $that->collapse->path; |
|
209
|
0
|
0
|
|
|
|
0
|
$self->debug("does $that match /^$this/ ??\n") if $DEBUG; |
|
210
|
0
|
|
|
|
|
0
|
$that =~ /^$this/; |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub below { |
|
214
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
215
|
0
|
|
0
|
|
|
0
|
my $that = shift || return $self->error_msg( bad_look => 'above' ); |
|
216
|
0
|
0
|
0
|
|
|
0
|
$that = $self->new("$that") unless blessed $that && $that->isa(__PACKAGE__); |
|
217
|
0
|
|
|
|
|
0
|
$that->above($self); |
|
218
|
|
|
|
|
|
|
} |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
sub base { |
|
221
|
3
|
|
|
3
|
1
|
8
|
my $self = shift; |
|
222
|
3
|
|
33
|
|
|
29
|
return $self->{ directory } || $self->{ path }; |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub parent { |
|
226
|
85
|
|
|
85
|
1
|
128
|
my $self = shift; |
|
227
|
85
|
|
100
|
|
|
199
|
my $skip = shift || 0; |
|
228
|
|
|
|
|
|
|
my $parent = $self->{ parent } |
|
229
|
|
|
|
|
|
|
||= $self->filesystem->directory( |
|
230
|
85
|
|
66
|
|
|
229
|
$self->{ directory } ||= $self->path_up |
|
|
|
|
66
|
|
|
|
|
|
231
|
|
|
|
|
|
|
); |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
return |
|
234
|
|
|
|
|
|
|
# don't return parents above the root |
|
235
|
85
|
100
|
|
|
|
414
|
$self->{ path } eq $parent->{ path } ? $self |
|
|
|
100
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# delegate to parent if there are generations to skip |
|
237
|
|
|
|
|
|
|
: $skip ? $parent->parent($skip - 1) |
|
238
|
|
|
|
|
|
|
# otherwise we've found the parent we're looking for |
|
239
|
|
|
|
|
|
|
: $parent; |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub path_up { |
|
243
|
20
|
|
|
20
|
1
|
26
|
my $self = shift; |
|
244
|
20
|
|
|
|
|
67
|
my $fs = $self->filesystem; |
|
245
|
20
|
|
|
|
|
45
|
my $path = $fs->split_directory($self->{ path }); |
|
246
|
|
|
|
|
|
|
|
|
247
|
20
|
50
|
|
|
|
49
|
$self->debug("split path [$path] into [", join(', ', @$path), "]\n") |
|
248
|
|
|
|
|
|
|
if $DEBUG; |
|
249
|
|
|
|
|
|
|
|
|
250
|
20
|
100
|
|
|
|
39
|
if (@$path > 1) { |
|
|
|
50
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
# multiple items in path can be relative or absolute - we're not |
|
252
|
|
|
|
|
|
|
# fussed. e.g. /foo/bar ==> /foo or foo/bar ==> foo |
|
253
|
17
|
|
|
|
|
21
|
pop(@$path); |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
elsif (@$path == 1) { |
|
256
|
|
|
|
|
|
|
# if there's a single item in a path then it's either a single |
|
257
|
|
|
|
|
|
|
# relative path item (e.g. 'foo' ==> ['foo']), in which case we |
|
258
|
|
|
|
|
|
|
# return the current working directory, or it's an empty item |
|
259
|
|
|
|
|
|
|
# indicating the root directory (e.g. '/' => ['']) in which case we |
|
260
|
|
|
|
|
|
|
# do nothing, because you can't go up from the root directory. |
|
261
|
3
|
50
|
|
|
|
8
|
if (length $path->[0]) { |
|
262
|
3
|
|
|
|
|
25
|
return $fs->cwd; |
|
263
|
|
|
|
|
|
|
} |
|
264
|
0
|
|
|
|
|
0
|
$self->not_implemented("going up from relative paths"); |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
else { |
|
267
|
0
|
|
|
|
|
0
|
$self->error("Invalid path (no elements)\n"); |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
|
|
270
|
17
|
|
|
|
|
37
|
return $fs->join_directory($path); |
|
271
|
|
|
|
|
|
|
} |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub exists { |
|
274
|
0
|
|
|
0
|
1
|
0
|
shift->stat; |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
sub must_exist { |
|
278
|
69
|
|
|
69
|
1
|
127
|
my $self = shift; |
|
279
|
|
|
|
|
|
|
|
|
280
|
69
|
100
|
|
|
|
171
|
unless ($self->exists) { |
|
281
|
4
|
50
|
33
|
|
|
29
|
if (@_ && $_[0]) { |
|
282
|
4
|
|
|
|
|
10
|
my $flag = shift; |
|
283
|
|
|
|
|
|
|
# true flag indicates we should attempt to create it |
|
284
|
4
|
|
|
|
|
60
|
$self->create(@_); # pass any other args, like dir file permission |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
else { |
|
287
|
0
|
|
|
|
|
0
|
return $self->error_msg( no_exist => $self->type, $self->{ path } ); |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
} |
|
290
|
69
|
|
|
|
|
212
|
return $self; |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub create { |
|
294
|
0
|
|
|
0
|
1
|
0
|
shift->not_implemented; |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
sub stat { |
|
298
|
38
|
|
|
38
|
1
|
72
|
my $self = shift->must_exist; |
|
299
|
|
|
|
|
|
|
my $stats = $self->filesystem->stat_path($self->{ path }) |
|
300
|
38
|
|
50
|
|
|
81
|
|| return $self->decline_msg( not_found => file => $self->{ path } ); |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# the definitive path can be tagged on the end |
|
303
|
|
|
|
|
|
|
# $self->{ definitive } = $stats->[STAT_PATH] |
|
304
|
|
|
|
|
|
|
# if defined $stats->[STAT_PATH]; |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
return wantarray |
|
307
|
38
|
50
|
|
|
|
151
|
? @$stats |
|
308
|
|
|
|
|
|
|
: $stats; |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub stats { |
|
312
|
59
|
|
66
|
59
|
1
|
176
|
my $stats = $_[0]->{ stats } ||= $_[0]->stat; |
|
313
|
|
|
|
|
|
|
return wantarray |
|
314
|
59
|
50
|
|
|
|
302
|
? @$stats |
|
315
|
|
|
|
|
|
|
: $stats; |
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
sub restat { |
|
319
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
320
|
0
|
|
|
|
|
0
|
delete $self->{ stats }; |
|
321
|
0
|
|
|
|
|
0
|
delete @$self{ keys %$TS_FIELD }; # timestamps for created, modified, etc. |
|
322
|
0
|
|
|
|
|
0
|
return $self->stats; |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub permissions { |
|
326
|
1
|
|
|
1
|
1
|
4
|
shift->mode & 0777; |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub chmod { |
|
330
|
1
|
|
|
1
|
1
|
4
|
my $self = shift; |
|
331
|
1
|
|
|
|
|
2
|
$self->filesystem->chmod_path($self->{ path }, @_); |
|
332
|
1
|
|
|
|
|
4
|
return $self; |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub basename { |
|
336
|
3
|
|
|
3
|
1
|
5
|
my $self = shift; |
|
337
|
3
|
|
|
|
|
10
|
my $name = $self->name; |
|
338
|
3
|
100
|
|
|
|
13
|
$name = $self->{ path } unless defined $name; |
|
339
|
3
|
|
|
|
|
48
|
$name =~ s/$MATCH_EXT//g; |
|
340
|
3
|
|
|
|
|
17
|
return $name; |
|
341
|
|
|
|
|
|
|
} |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
sub extension { |
|
344
|
2
|
|
|
2
|
1
|
4
|
my $self = shift; |
|
345
|
2
|
50
|
|
|
|
22
|
return $self->{ path } =~ $MATCH_EXT |
|
346
|
|
|
|
|
|
|
? $1 |
|
347
|
|
|
|
|
|
|
: ''; |
|
348
|
|
|
|
|
|
|
} |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub filesystem { |
|
351
|
1170
|
|
|
1170
|
1
|
1411
|
my $self = shift; |
|
352
|
1170
|
100
|
|
|
|
2265
|
return $self->class->any_var('FILESYSTEM')->prototype |
|
353
|
|
|
|
|
|
|
unless ref $self; |
|
354
|
|
|
|
|
|
|
$self->{ filesystem } |
|
355
|
1169
|
|
66
|
|
|
4004
|
||= $self->class->any_var('FILESYSTEM')->prototype; |
|
356
|
|
|
|
|
|
|
} |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub visit { |
|
359
|
14
|
|
|
14
|
1
|
56
|
my $self = shift; |
|
360
|
14
|
|
|
|
|
26
|
my $visitor = $self->filesystem->visitor(@_); |
|
361
|
14
|
|
|
|
|
50
|
$visitor->visit($self); |
|
362
|
14
|
|
|
|
|
88
|
return $visitor; |
|
363
|
|
|
|
|
|
|
} |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub collect { |
|
366
|
2
|
|
|
2
|
1
|
7
|
shift->visit(@_)->collect; |
|
367
|
|
|
|
|
|
|
} |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
sub enter { |
|
370
|
|
|
|
|
|
|
# enter() is a custom accept() method for the entry point of a visitor |
|
371
|
0
|
|
|
0
|
1
|
0
|
shift->accept; |
|
372
|
|
|
|
|
|
|
} |
|
373
|
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
sub accept { |
|
375
|
0
|
|
|
0
|
1
|
0
|
$_[1]->visit_path($_[0]); |
|
376
|
|
|
|
|
|
|
} |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
sub metadata { |
|
379
|
3
|
|
|
3
|
1
|
8
|
my $self = shift; |
|
380
|
3
|
|
100
|
|
|
12
|
my $meta = $self->{ metadata } ||= { }; |
|
381
|
3
|
100
|
|
|
|
15
|
if (@_ == 1) { |
|
|
|
100
|
|
|
|
|
|
|
382
|
1
|
|
|
|
|
5
|
return $meta->{ $_[0] }; |
|
383
|
|
|
|
|
|
|
} |
|
384
|
|
|
|
|
|
|
elsif (@_ > 1) { |
|
385
|
1
|
|
|
|
|
3
|
while (@_) { |
|
386
|
1
|
|
|
|
|
1
|
my $key = shift; |
|
387
|
1
|
|
|
|
|
4
|
$meta->{ $key } = shift; |
|
388
|
|
|
|
|
|
|
} |
|
389
|
|
|
|
|
|
|
} |
|
390
|
2
|
|
|
|
|
6
|
return $meta; |
|
391
|
|
|
|
|
|
|
} |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
1; |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=encoding utf8 |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=head1 NAME |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
Badger::Filesystem::Path - generic filesystem path object |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
# using Badger::Filesytem constructor subroutine |
|
404
|
|
|
|
|
|
|
use Badger::Filesystem 'Path'; |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
# use native OS-specific paths: |
|
407
|
|
|
|
|
|
|
$path = Path('/path/to/something'); |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# or generic OS-independant paths |
|
410
|
|
|
|
|
|
|
$path = Path('path', 'to', 'something'); |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
# manual object construction |
|
413
|
|
|
|
|
|
|
use Badger::Filesystem::Path; |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# positional arguments |
|
416
|
|
|
|
|
|
|
$path = Badger::Filesystem::Path->new('/path/to/something'); |
|
417
|
|
|
|
|
|
|
$path = Badger::Filesystem::Path->new(['path', 'to', 'something']); |
|
418
|
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
# named parameters |
|
420
|
|
|
|
|
|
|
$path = Badger::Filesystem::Path->new( |
|
421
|
|
|
|
|
|
|
path => '/path/to/something' |
|
422
|
|
|
|
|
|
|
); |
|
423
|
|
|
|
|
|
|
$path = Badger::Filesystem::Path->new( |
|
424
|
|
|
|
|
|
|
path => ['path', 'to', 'something'] |
|
425
|
|
|
|
|
|
|
); |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
# path inspection methods |
|
428
|
|
|
|
|
|
|
$path->path; # current path |
|
429
|
|
|
|
|
|
|
$path->base; # parent directory or path itself |
|
430
|
|
|
|
|
|
|
$path->parent; # directory object for base |
|
431
|
|
|
|
|
|
|
$path->extension # filename .XXX extension |
|
432
|
|
|
|
|
|
|
$path->basename # filename without .XXX extension |
|
433
|
|
|
|
|
|
|
$path->is_absolute; # path is absolute |
|
434
|
|
|
|
|
|
|
$path->is_relative; # path is relative |
|
435
|
|
|
|
|
|
|
$path->exists; # returns true/false |
|
436
|
|
|
|
|
|
|
$path->must_exist; # throws error if not |
|
437
|
|
|
|
|
|
|
@stats = $path->stat; # returns list |
|
438
|
|
|
|
|
|
|
$stats = $path->stat; # returns list ref |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
# path translation methods |
|
441
|
|
|
|
|
|
|
$path->relative; # relative to cwd |
|
442
|
|
|
|
|
|
|
$path->relative($base); # relative to $base |
|
443
|
|
|
|
|
|
|
$path->absolute; # relative to filesystem root |
|
444
|
|
|
|
|
|
|
$path->definitive; # physical file location |
|
445
|
|
|
|
|
|
|
$path->collapse; # resolve '.' and '..' in $path |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
# path comparison methods |
|
448
|
|
|
|
|
|
|
$path->above($another_path); # $path is ancestor of $another_path |
|
449
|
|
|
|
|
|
|
$path->below($another_path); # $path is descendant of $another_path |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=head1 INTRODUCTION |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
This is the documentation for the C module. |
|
454
|
|
|
|
|
|
|
It defines a base class object for the L and |
|
455
|
|
|
|
|
|
|
L objects which inherit (and in some cases |
|
456
|
|
|
|
|
|
|
redefine) the methods described below. |
|
457
|
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
In other words, you should read this documentation first if you're working |
|
459
|
|
|
|
|
|
|
with L or L objects. |
|
460
|
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
The C module defines a base class object for |
|
464
|
|
|
|
|
|
|
representing paths in a real or virtual file system. |
|
465
|
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
You can create a generic path object (e.g. to represent a path that doesn't |
|
467
|
|
|
|
|
|
|
relate to a specific file or directory in a file system), using the C |
|
468
|
|
|
|
|
|
|
constructor method in L. |
|
469
|
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
use Badger::Filesystem 'Path'; |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
my $path = Path('/path/to/something'); |
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
However in most cases you'll want to create a file or directory subclass |
|
475
|
|
|
|
|
|
|
object. The easiest way to do that is like this: |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
use Badger::Filesystem 'File Path'; |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
my $file = File('/path/to/file'); |
|
480
|
|
|
|
|
|
|
my $dir = Dir('/path/to/dir'); |
|
481
|
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
If you're concerned about portability to other operating systems and/or |
|
483
|
|
|
|
|
|
|
file systems, then you can specify paths as a list or reference to a list |
|
484
|
|
|
|
|
|
|
of component names. |
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
my $file = File('path', 'to', 'file'); |
|
487
|
|
|
|
|
|
|
my $dir = Dir(['path', 'to', 'dir']); |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
=head1 METHODS |
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
=head2 new($path) |
|
492
|
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
Constructor method to create a new C object. |
|
494
|
|
|
|
|
|
|
The path can be specified as a single positional argument, either as a |
|
495
|
|
|
|
|
|
|
text string or reference to list of path components. |
|
496
|
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
# single text string |
|
498
|
|
|
|
|
|
|
$path = Badger::Filesystem::Path->new('/path/to/something'); |
|
499
|
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
# reference to list |
|
501
|
|
|
|
|
|
|
$path = Badger::Filesystem::Path->new(['path', 'to', 'something']); |
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
It can also be specified as a C named parameter. |
|
504
|
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
# named parameter list |
|
506
|
|
|
|
|
|
|
$path = Badger::Filesystem::Path->new( |
|
507
|
|
|
|
|
|
|
path => '/path/to/something' |
|
508
|
|
|
|
|
|
|
); |
|
509
|
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
# reference to hash of named parameter(s) |
|
511
|
|
|
|
|
|
|
$path = Badger::Filesystem::Path->new({ |
|
512
|
|
|
|
|
|
|
path => '/path/to/something' |
|
513
|
|
|
|
|
|
|
}); |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
The constructor method also recognises the C named parameter which |
|
516
|
|
|
|
|
|
|
can contain a reference to the L object or class that |
|
517
|
|
|
|
|
|
|
created it. In most cases you can rely on the L to create |
|
518
|
|
|
|
|
|
|
path objects for you, using either the L |
|
519
|
|
|
|
|
|
|
method, or the L subroutine. |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
use Badger::Filesystem 'FS Path'; |
|
522
|
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
# FS is alias for 'Badger::Filesystem' |
|
524
|
|
|
|
|
|
|
# Path() is constructor subrooutine |
|
525
|
|
|
|
|
|
|
my $path; |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
# using the path() method |
|
528
|
|
|
|
|
|
|
$path = FS->path('/path/to/something'); |
|
529
|
|
|
|
|
|
|
$path = FS->path('path', 'to', 'something'); |
|
530
|
|
|
|
|
|
|
$path = FS->path(['path', 'to', 'something']); |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
# using the Path() subroutine |
|
533
|
|
|
|
|
|
|
$path = Path('/path/to/something'); |
|
534
|
|
|
|
|
|
|
$path = Path('path', 'to', 'something'); |
|
535
|
|
|
|
|
|
|
$path = Path(['path', 'to', 'something']); |
|
536
|
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
The examples that follow will use the C constructor subroutine. |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=head2 init(\%config) |
|
540
|
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
Default initialisation method which subclasses (e.g. |
|
542
|
|
|
|
|
|
|
L and L) can |
|
543
|
|
|
|
|
|
|
redefine. |
|
544
|
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
=head2 path() |
|
546
|
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
This method returns the path as a text string. It is called automatically |
|
548
|
|
|
|
|
|
|
whenever the path object is stringified. |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
=head2 is_absolute() |
|
551
|
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
Returns true if the path is absolute, false if not. |
|
553
|
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=head2 is_relative() |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
Returns true if the path is relative, false if not. |
|
557
|
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
=head2 absolute($base) |
|
559
|
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
Returns an absolute representation of the path, relative to the C<$base> |
|
561
|
|
|
|
|
|
|
path passed as an argument, or the current working directory if C<$base> |
|
562
|
|
|
|
|
|
|
is not specified. |
|
563
|
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
# assume cwd is /foo/bar, |
|
565
|
|
|
|
|
|
|
my $path = Path('/baz/bam'); |
|
566
|
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
print $path->absolute; # /foo/bar/baz/bam |
|
568
|
|
|
|
|
|
|
print $path->absolute('/wiz'); # /wiz/baz/bam |
|
569
|
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
=head2 relative($base) |
|
571
|
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
Returns a relative representation of the path, relative to the C<$base> |
|
573
|
|
|
|
|
|
|
path passed as an argument, or the current working directory if C<$base> |
|
574
|
|
|
|
|
|
|
is not specified. |
|
575
|
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
# assume cwd is /foo/bar, |
|
577
|
|
|
|
|
|
|
my $path = Path('/foo/bar/baz/bam'); |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
print $path->relative; # /baz/bam |
|
580
|
|
|
|
|
|
|
print $path->relative('/foo'); # /bar/baz/bam |
|
581
|
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
=head2 definitive() |
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
Returns the definitive representation of the path which in most cases will |
|
585
|
|
|
|
|
|
|
be the same as the L path. |
|
586
|
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
However, if you're using a L, |
|
588
|
|
|
|
|
|
|
then the I path I include the virtual root directory, |
|
589
|
|
|
|
|
|
|
whereas a the I path will I. |
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
my $vfs = Badger::Filesystem::Virtual->new( root => '/my/vfs' ); |
|
592
|
|
|
|
|
|
|
my $path = $vfs->file('/foo/bar'); |
|
593
|
|
|
|
|
|
|
print $path->absolute; # /foo/bar |
|
594
|
|
|
|
|
|
|
print $path->definitive; # /my/vfs/foo/bar |
|
595
|
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=head2 canonical() |
|
597
|
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
This method returns the canonical representation of the path. In most cases |
|
599
|
|
|
|
|
|
|
this is the same as the absolute path (in fact the base class aliases the |
|
600
|
|
|
|
|
|
|
C method directly to the L method). |
|
601
|
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
print Path('foo')->canonical; # /your/current/path/foo |
|
603
|
|
|
|
|
|
|
print Path('/foo/bar')->canonical; # /foo/bar |
|
604
|
|
|
|
|
|
|
print Path('/foo/bar/')->canonical; # /foo/bar |
|
605
|
|
|
|
|
|
|
print Path('/foo/bar.txt')->canonical; # /foo/bar.txt |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
Note that the C base class will I any |
|
608
|
|
|
|
|
|
|
trailing slashes (or whatever the appropriate directory separator is for your |
|
609
|
|
|
|
|
|
|
filesystem) from the end of an absolute path. |
|
610
|
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
In the case of directories, implemented by the |
|
612
|
|
|
|
|
|
|
L subclass, a trailing slash (or relevant |
|
613
|
|
|
|
|
|
|
separator for your filesystem) will be added. |
|
614
|
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
print Dir('/foo/bar')->canonical; # /foo/bar/ |
|
616
|
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
This is done by delegation to the |
|
618
|
|
|
|
|
|
|
L method in |
|
619
|
|
|
|
|
|
|
L. |
|
620
|
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
=head2 collapse() |
|
622
|
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
Reduces the path to its simplest form by resolving and removing any C<.> |
|
624
|
|
|
|
|
|
|
(current directory) and C<..> (parent directory) components (or whatever the |
|
625
|
|
|
|
|
|
|
corresponding tokens are for the current and parent directories of your |
|
626
|
|
|
|
|
|
|
filesystem). |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
my $path = Path('/foo/bar/../baz')->collapse; |
|
629
|
|
|
|
|
|
|
print $path; # /foo/baz |
|
630
|
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
See the L method in |
|
632
|
|
|
|
|
|
|
L for further information. |
|
633
|
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
=head2 above($child) |
|
635
|
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
Returns true if the path is "above" the C<$child> path passed as an argument. |
|
637
|
|
|
|
|
|
|
Formally, we say that the path is an I of C<$child> meaning that it |
|
638
|
|
|
|
|
|
|
is the parent directory, or grand-parent, or great-grand-parent, and so on. |
|
639
|
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
my $parent = Path('/foo/bar'); |
|
641
|
|
|
|
|
|
|
my $child = Path('/foo/bar/baz'); |
|
642
|
|
|
|
|
|
|
$parent->above($child); # true |
|
643
|
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
This is implemented as a simple prefix match. That is, the parent path must |
|
645
|
|
|
|
|
|
|
appear at the start of the child path. Consequently, this method will not |
|
646
|
|
|
|
|
|
|
account for symbolic links or other similar filesystem features, and it may |
|
647
|
|
|
|
|
|
|
not work properly on systems that don't follow this convention (although there |
|
648
|
|
|
|
|
|
|
are none that I'm aware of). |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=head2 below($parent) |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
Returns true if the path is "below" the C<$parent> path passed as an argument. |
|
653
|
|
|
|
|
|
|
Formally, we say that the path is a I of C<$parent> meaning that it |
|
654
|
|
|
|
|
|
|
is an immediate sub-directory, or sub-sub-directory, and so on. |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
my $parent = Path('/foo/bar'); |
|
657
|
|
|
|
|
|
|
my $child = Path('/foo/bar/baz'); |
|
658
|
|
|
|
|
|
|
$child->below($parent); # true |
|
659
|
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
Like L, this is implemented using a simple prefix match. |
|
661
|
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=head2 base() |
|
663
|
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
Returns the base directory of a path. For L and |
|
665
|
|
|
|
|
|
|
L objects, this method will return the complete |
|
666
|
|
|
|
|
|
|
path. |
|
667
|
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
print Path('/foo/bar')->base; # /foo/bar |
|
669
|
|
|
|
|
|
|
print Directory('/foo/bar')->base; # /foo/bar |
|
670
|
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
However the L module returns the parent directory in |
|
672
|
|
|
|
|
|
|
which the file is located. |
|
673
|
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
print File('/foo/bar')->base; # /foo |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
=head2 parent($skip_generations) / up($skip_generations) |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
Returns a L object representing the parent |
|
679
|
|
|
|
|
|
|
directory for a path. |
|
680
|
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
Path->('/foo/bar')->parent; # path object for /foo |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
A numerical argument can be provided to indicate the number of generation |
|
684
|
|
|
|
|
|
|
you want to skip. A value of C<0> is the same as providing no argument - it |
|
685
|
|
|
|
|
|
|
returns the parent. A value of C<1> skips the parent and returns the |
|
686
|
|
|
|
|
|
|
grand-parent, and so on. |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
Path->('/foo/bar/baz/bam')->parent(2); # path object for /foo |
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
The root directory will be returned if you try to skip too many generations. |
|
691
|
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
Path->('/foo/bar/baz/bam')->parent(20); # path object for / |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=head2 path_up() |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
This returns a text string representing the parent of a path. If the path |
|
697
|
|
|
|
|
|
|
contains multiple items (e.g. '/foo/bar' or 'foo/bar') then the last item |
|
698
|
|
|
|
|
|
|
will be removed (e.g. resulting in '/foo' or 'foo' respectively). If an |
|
699
|
|
|
|
|
|
|
absolute path contains one item or none (e.g. '/foo' or '/') then the |
|
700
|
|
|
|
|
|
|
root directory ('/') will be returned. A relative path with only one item |
|
701
|
|
|
|
|
|
|
(e.g. 'foo') is assumed to be relative to the current working directory |
|
702
|
|
|
|
|
|
|
which will be returned (e.g. '/path/to/current/dir'). |
|
703
|
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
=head2 exists() |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
Returns true if the path exists in the filesystem (e.g. as a file, directory, |
|
707
|
|
|
|
|
|
|
or some other entry), or false if not. |
|
708
|
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
if ($path->exists) { |
|
710
|
|
|
|
|
|
|
print "$path already exists\n"; |
|
711
|
|
|
|
|
|
|
} |
|
712
|
|
|
|
|
|
|
else { |
|
713
|
|
|
|
|
|
|
print "Creating $path\n"; |
|
714
|
|
|
|
|
|
|
# ...etc... |
|
715
|
|
|
|
|
|
|
} |
|
716
|
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
=head2 must_exist($create) |
|
718
|
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
Checks that the path exists (by calling L) and throws an error |
|
720
|
|
|
|
|
|
|
if it doesn't. |
|
721
|
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
$path->must_exist; # no need to check return value |
|
723
|
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
The C<$create> flag can be set to have it attempt to L itself if it |
|
725
|
|
|
|
|
|
|
doesn't already exist. However, this only makes sense for file and directory |
|
726
|
|
|
|
|
|
|
subclasses and not base class paths. |
|
727
|
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
$dir->must_exist(1); # create if it doesn't |
|
729
|
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=head2 create() |
|
731
|
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
In the base class this will method will throw an error. You can't physically |
|
733
|
|
|
|
|
|
|
create an abstract path unless you know what kind of concrete entity (e.g. |
|
734
|
|
|
|
|
|
|
file or directory) it maps onto. In other words, the L method will |
|
735
|
|
|
|
|
|
|
only work for the L and |
|
736
|
|
|
|
|
|
|
L subclasses. |
|
737
|
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
$path->create; # FAIL |
|
739
|
|
|
|
|
|
|
$dir->create; # OK |
|
740
|
|
|
|
|
|
|
$file->create; # OK |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=head2 chmod($perms) |
|
743
|
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
This method changes the file permissions on a file or directory. |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
$file->chmod(0775); |
|
747
|
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
=head2 stat() |
|
749
|
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
Performs a filesystem C on the path and returns a list (in list |
|
751
|
|
|
|
|
|
|
context), or a reference to a list (in scalar context) containing the 13 |
|
752
|
|
|
|
|
|
|
information elements. |
|
753
|
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
@list = $path->stat; # list context |
|
755
|
|
|
|
|
|
|
$list = $path->stat; # scalar context |
|
756
|
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
A summary of the fields is shown below. See C for complete |
|
758
|
|
|
|
|
|
|
details. Each of the individual fields can also be accessed via their own |
|
759
|
|
|
|
|
|
|
methods, also listed in the table. |
|
760
|
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
Field Method Description |
|
762
|
|
|
|
|
|
|
------------------------------------------------------------------------ |
|
763
|
|
|
|
|
|
|
0 device() device number of filesystem |
|
764
|
|
|
|
|
|
|
1 inoode() inode number |
|
765
|
|
|
|
|
|
|
2 mode() file mode (type and permissions) |
|
766
|
|
|
|
|
|
|
3 links() number of (hard) links to the file |
|
767
|
|
|
|
|
|
|
4 user() numeric user ID of file’s owner |
|
768
|
|
|
|
|
|
|
5 group() numeric group ID of file’s owner |
|
769
|
|
|
|
|
|
|
6 device_type() the device identifier (special files only) |
|
770
|
|
|
|
|
|
|
7 size() total size of file, in bytes |
|
771
|
|
|
|
|
|
|
8 atime() last access time in seconds since the epoch |
|
772
|
|
|
|
|
|
|
9 mtime() last modify time in seconds since the epoch |
|
773
|
|
|
|
|
|
|
10 ctime() inode change time in seconds since the epoch (*) |
|
774
|
|
|
|
|
|
|
11 block_size() preferred block size for file system I/O |
|
775
|
|
|
|
|
|
|
12 blocks() actual number of blocks allocated |
|
776
|
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
In addition to those that are returned by Perl's inbuilt C function, |
|
778
|
|
|
|
|
|
|
this method returns four additional flags. |
|
779
|
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
13 readable() file is readable by current process |
|
781
|
|
|
|
|
|
|
14 writeable() file is writeable by current process |
|
782
|
|
|
|
|
|
|
15 executable() file is executable by current process |
|
783
|
|
|
|
|
|
|
16 owner() file is owned by current process |
|
784
|
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
=head2 stats() |
|
786
|
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
A wrapper around the L method which caches the results to avoid |
|
788
|
|
|
|
|
|
|
making repeated filesystem calls. |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
@list = $path->stats; # list context |
|
791
|
|
|
|
|
|
|
$list = $path->stats; # scalar context |
|
792
|
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
Note that the L, L and L methods also |
|
794
|
|
|
|
|
|
|
cache the L objects they create to represent the |
|
795
|
|
|
|
|
|
|
access, creation and modification times respectively. |
|
796
|
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
=head2 restat() |
|
798
|
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
Clears any cached values stored by the L, L, |
|
800
|
|
|
|
|
|
|
L and L methods and calls L to reload |
|
801
|
|
|
|
|
|
|
(and re-cache) the data from a L call. |
|
802
|
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
=head2 device() |
|
804
|
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
Returns the device number for the file. See L. |
|
806
|
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
=head2 inode() |
|
808
|
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
Returns the inode number for the file. See L. |
|
810
|
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
=head2 mode() |
|
812
|
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
Returns the file mode for the file. Note that this contains both the |
|
814
|
|
|
|
|
|
|
file type and permissions. See L. |
|
815
|
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
=head2 permissions() / perms() |
|
817
|
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
Returns the file permissions. This is equivalent to |
|
819
|
|
|
|
|
|
|
C<< $file->mode & 0777 >>. |
|
820
|
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
=head2 links() |
|
822
|
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
Returns the number of hard links to the file. See L. |
|
824
|
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
=head2 user() |
|
826
|
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
Returns the numeric user ID of the file's owner. See L. |
|
828
|
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
=head2 group() |
|
830
|
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
Returns the numeric group ID of the file's group. See L. |
|
832
|
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
=head2 device_type() |
|
834
|
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
Returns the device identifier (for special files only). See L. |
|
836
|
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
=head2 size() |
|
838
|
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
Returns the total size of the file in bytes. See L. |
|
840
|
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
=head2 atime() |
|
842
|
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
Returns the time (in seconds since the epoch) that the file was last accessed. |
|
844
|
|
|
|
|
|
|
See L. |
|
845
|
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
=head2 accessed() |
|
847
|
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
Returns a L object for the L value. This object |
|
849
|
|
|
|
|
|
|
will auto-stringify to produce an ISO-8601 formatted date. You can also |
|
850
|
|
|
|
|
|
|
call various methods to access different parts of the time and/or date. |
|
851
|
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
print $file->accessed; # 2009/04/20 16:25:00 |
|
853
|
|
|
|
|
|
|
print $file->accessed->date; # 2009/04/20 |
|
854
|
|
|
|
|
|
|
print $file->accessed->year; # 2009 |
|
855
|
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
=head2 mtime() |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
Returns the time (in seconds since the epoch) that the file was last modified. |
|
859
|
|
|
|
|
|
|
See L. |
|
860
|
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
=head2 modified() |
|
862
|
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
Returns a L object for the L value. |
|
864
|
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
print $file->modified; # 2009/04/20 16:25:00 |
|
866
|
|
|
|
|
|
|
print $file->modified->time; # 16:25:0 |
|
867
|
|
|
|
|
|
|
print $file->modified->hour; # 16 |
|
868
|
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
=head2 ctime() |
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
Returns the time (in seconds since the epoch) that the file was created. See |
|
872
|
|
|
|
|
|
|
L. |
|
873
|
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
=head2 created() |
|
875
|
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
Returns a L object for the L value. |
|
877
|
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
print $file->created; # 2009/04/20 16:25:00 |
|
879
|
|
|
|
|
|
|
print $file->created->date; # 2009/04/20 |
|
880
|
|
|
|
|
|
|
print $file->created->time; # 16:25:00 |
|
881
|
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
=head2 block_size() |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
Returns the preferred block size for file system I/O on the file. See |
|
885
|
|
|
|
|
|
|
L. |
|
886
|
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
=head2 blocks() |
|
888
|
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
Returns the actual number of blocks allocated to the file. See L. |
|
890
|
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
=head2 readable() |
|
892
|
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
Returns a true value if the file is readable by the current user (i.e. the |
|
894
|
|
|
|
|
|
|
owner of the current process), false if not. See L. |
|
895
|
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
=head2 writeable() |
|
897
|
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
Returns a true value if the file is writeable by the current user (i.e. the |
|
899
|
|
|
|
|
|
|
owner of the current process), false if not. See L. |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
=head2 executable() |
|
902
|
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
Returns a true value if the file is executable by the current user (i.e. the |
|
904
|
|
|
|
|
|
|
owner of the current process), false if not. See L. |
|
905
|
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
=head2 owner() |
|
907
|
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
Returns a true value if the file is owned by the current user (i.e. the |
|
909
|
|
|
|
|
|
|
owner of the current process), false if not. See L. |
|
910
|
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
=head2 filesystem() |
|
912
|
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
Returns a reference to a L object, or the name of the |
|
914
|
|
|
|
|
|
|
filesystem class (e.g. L or a subclass) that created |
|
915
|
|
|
|
|
|
|
the path object. If this is undefined then the default value defined in |
|
916
|
|
|
|
|
|
|
the L<$FILESYSTEM> class variable is returned. Unless you've changed it, |
|
917
|
|
|
|
|
|
|
or re-defined it in a subclass, this value will be C. |
|
918
|
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
The end result is that you can use the C method to access a |
|
920
|
|
|
|
|
|
|
L object or class through which you can perform other |
|
921
|
|
|
|
|
|
|
filesystem related operations. This is used internally by a number of |
|
922
|
|
|
|
|
|
|
method. |
|
923
|
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
# access filesystem via existing path |
|
925
|
|
|
|
|
|
|
$path->filesystem->dir('/a/new/directory/object'); |
|
926
|
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
# same as |
|
928
|
|
|
|
|
|
|
Badger::Filesystem->dir('/a/new/directory/object'); |
|
929
|
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
=head2 visit($visitor) |
|
931
|
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
Entry point for a filesystem visitor to visit a filesystem path. A |
|
933
|
|
|
|
|
|
|
reference to a L object (or subclass) should |
|
934
|
|
|
|
|
|
|
be passed as the first argument. |
|
935
|
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
use Badger::Filesystem::Visitor; |
|
937
|
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
my $visitor = Badger::Filesystem::Visitor->new( recurse => 1 ); |
|
939
|
|
|
|
|
|
|
$path->visit($visitor); |
|
940
|
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
Alternately, a list or reference to a hash array of named parameters may be |
|
942
|
|
|
|
|
|
|
provided. These will be used to instantiate a new |
|
943
|
|
|
|
|
|
|
L object (via the L |
|
944
|
|
|
|
|
|
|
L method) which will then be |
|
945
|
|
|
|
|
|
|
applied to the path. If no arguments are passed then a visitor is created |
|
946
|
|
|
|
|
|
|
with a default configuration. |
|
947
|
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
# either list of named params |
|
949
|
|
|
|
|
|
|
$path->visit( recurse => 1 ); |
|
950
|
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
# or reference to hash array |
|
952
|
|
|
|
|
|
|
$path->visit({ recurse => 1}); |
|
953
|
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
The method then calls the visitor |
|
955
|
|
|
|
|
|
|
L passing C<$self> as an argument |
|
956
|
|
|
|
|
|
|
to begin the visit. |
|
957
|
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
=head2 accept($visitor) |
|
959
|
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
This method is called to dispatch a visitor to the correct method for a |
|
961
|
|
|
|
|
|
|
filesystem object. In the L base class, it calls the |
|
962
|
|
|
|
|
|
|
visitor L method, |
|
963
|
|
|
|
|
|
|
passing the C<$self> object reference as an argument. Subclasses redefine this |
|
964
|
|
|
|
|
|
|
method to call other visitor methods. |
|
965
|
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
=head2 enter($visitor) |
|
967
|
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
This is a special case of the L method which subclasses (e.g. |
|
969
|
|
|
|
|
|
|
L) use to differentiate between the |
|
970
|
|
|
|
|
|
|
initial entry point of a visitor and subsequent visits to directories |
|
971
|
|
|
|
|
|
|
contained therein. In the base class it simply delegates to the L |
|
972
|
|
|
|
|
|
|
method. |
|
973
|
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
=head2 collect(\%params) |
|
975
|
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
This is a short-cut to call the L method and then the |
|
977
|
|
|
|
|
|
|
L method on the |
|
978
|
|
|
|
|
|
|
L object returned. |
|
979
|
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
# short form |
|
981
|
|
|
|
|
|
|
my @items = $path->collect( files => 1, dirs => 0 ); |
|
982
|
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
# long form |
|
984
|
|
|
|
|
|
|
my @items = $path->visit( files => 1, dirs => 0 )->collect; |
|
985
|
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
=head2 metadata() / meta() |
|
987
|
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
This method allows you to associate metadata with a path. The method |
|
989
|
|
|
|
|
|
|
accepts multiple arguments to set metadata: |
|
990
|
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
$path->metadata( title => 'An Example', author => 'Arthur Dent' ); |
|
992
|
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
It also accepts a single argument to fetch a metadata item: |
|
994
|
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
print $path->metadata('author'); # Arthur Dent |
|
996
|
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
You can also call it without arguments. The method returns a reference |
|
998
|
|
|
|
|
|
|
to a hash array of metadata items. |
|
999
|
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
my $meta = $path->metadata; |
|
1001
|
|
|
|
|
|
|
print $meta->{ author }; # Arthur Dent |
|
1002
|
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
=head1 STUB METHODS |
|
1004
|
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
The following methods serve little or no purpose in the |
|
1006
|
|
|
|
|
|
|
C base class. They are redefined by the |
|
1007
|
|
|
|
|
|
|
C and C modules |
|
1008
|
|
|
|
|
|
|
to do the right thing. |
|
1009
|
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
=head2 is_file() |
|
1011
|
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
This method always returns false in the C base |
|
1013
|
|
|
|
|
|
|
class. The C subclass redefines this to return |
|
1014
|
|
|
|
|
|
|
true. NOTE: this may be changed to examine the filesystem and return true |
|
1015
|
|
|
|
|
|
|
if the path references a file. |
|
1016
|
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
=head2 is_directory() / is_dir() |
|
1018
|
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
This method always returns false in the C base |
|
1020
|
|
|
|
|
|
|
class. The C subclass redefines this to return |
|
1021
|
|
|
|
|
|
|
true. NOTE: this may be changed to examine the filesystem and return true |
|
1022
|
|
|
|
|
|
|
if the path references a file. |
|
1023
|
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
=head2 volume() / vol() |
|
1025
|
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
Returns any volume defined as part of the path. This method does nothing in |
|
1027
|
|
|
|
|
|
|
the C base class. |
|
1028
|
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
=head2 directory() / dir() |
|
1030
|
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
Returns the directory portion of a path. This method does nothing in the |
|
1032
|
|
|
|
|
|
|
C base class. |
|
1033
|
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
=head2 name() |
|
1035
|
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
Returns the file name portion of a path. This method does nothing in the |
|
1037
|
|
|
|
|
|
|
C base class. |
|
1038
|
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
=head2 extension() / ext() |
|
1040
|
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
Returns any file extension portion following the final C<.> in the path. |
|
1042
|
|
|
|
|
|
|
This works in the C base class by looking at the |
|
1043
|
|
|
|
|
|
|
full path. |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
print Path('/foo/bar.txt')->extension; # txt |
|
1046
|
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
=head2 basename() / base_name() |
|
1048
|
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
Returns the filename I the file extension following the final |
|
1050
|
|
|
|
|
|
|
C<.> in the path. This works (for some definition of "works") in the |
|
1051
|
|
|
|
|
|
|
C base class by looking at the path L, |
|
1052
|
|
|
|
|
|
|
if defined, or the full C if not. Note that this will produce |
|
1053
|
|
|
|
|
|
|
unexpected results in some cases due to the fact that the base class |
|
1054
|
|
|
|
|
|
|
does not define a value for L. e.g. |
|
1055
|
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
print Path('/foo/bar.txt')->basename; # /foo/bar |
|
1057
|
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
However, in most cases you would be using this through a |
|
1059
|
|
|
|
|
|
|
L subclass which will product the correct |
|
1060
|
|
|
|
|
|
|
results. |
|
1061
|
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
print File('/foo/bar.txt')->basename; # bar |
|
1063
|
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
=head1 AUTHOR |
|
1065
|
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
Andy Wardley L |
|
1067
|
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
1069
|
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
Copyright (C) 2005-2009 Andy Wardley. All rights reserved. |
|
1071
|
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
|
1073
|
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
The C modules are built around a number of existing |
|
1075
|
|
|
|
|
|
|
Perl modules, including L, L, L, L, |
|
1076
|
|
|
|
|
|
|
L and draw heavily on ideas in L. |
|
1077
|
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
Please see the L |
|
1079
|
|
|
|
|
|
|
in L for further information. |
|
1080
|
|
|
|
|
|
|
|
|
1081
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
1082
|
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
L, |
|
1084
|
|
|
|
|
|
|
L, |
|
1085
|
|
|
|
|
|
|
L, |
|
1086
|
|
|
|
|
|
|
L. |
|
1087
|
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
=cut |
|
1089
|
|
|
|
|
|
|
|
|
1090
|
|
|
|
|
|
|
# Local Variables: |
|
1091
|
|
|
|
|
|
|
# mode: Perl |
|
1092
|
|
|
|
|
|
|
# perl-indent-level: 4 |
|
1093
|
|
|
|
|
|
|
# indent-tabs-mode: nil |
|
1094
|
|
|
|
|
|
|
# End: |
|
1095
|
|
|
|
|
|
|
# |
|
1096
|
|
|
|
|
|
|
# vim: expandtab shiftwidth=4: |
|
1097
|
|
|
|
|
|
|
# TextMate: should support split pane editing |