line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Parse::Path; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '0.92'; # VERSION |
4
|
|
|
|
|
|
|
# ABSTRACT: Parser for paths |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
############################################################################# |
7
|
|
|
|
|
|
|
# Modules |
8
|
|
|
|
|
|
|
|
9
|
6
|
|
|
6
|
|
312066
|
use sanity; |
|
6
|
|
|
|
|
3071544
|
|
|
6
|
|
|
|
|
99
|
|
10
|
|
|
|
|
|
|
|
11
|
6
|
|
|
6
|
|
2755523
|
use Scalar::Util qw( blessed ); |
|
6
|
|
|
|
|
18
|
|
|
6
|
|
|
|
|
779
|
|
12
|
6
|
|
|
6
|
|
39
|
use Module::Runtime qw( use_module ); |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
47
|
|
13
|
|
|
|
|
|
|
|
14
|
6
|
|
|
6
|
|
6131
|
use namespace::clean; |
|
6
|
|
|
|
|
156936
|
|
|
6
|
|
|
|
|
46
|
|
15
|
6
|
|
|
6
|
|
1185
|
no warnings 'uninitialized'; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
3031
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
############################################################################# |
18
|
|
|
|
|
|
|
# Dispatcher |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub new { |
21
|
80
|
|
|
80
|
0
|
46642
|
my $class = shift; |
22
|
80
|
|
|
|
|
153
|
my %opts; |
23
|
|
|
|
|
|
|
|
24
|
80
|
50
|
|
|
|
273
|
if (@_ == 1) { |
25
|
|
|
|
|
|
|
# XXX: Many of these forms are purposely undocumented and experimental |
26
|
0
|
|
|
|
|
0
|
my $arg = pop; |
27
|
0
|
0
|
|
|
|
0
|
if (blessed $arg) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
28
|
0
|
0
|
|
|
|
0
|
if ($arg->does('Parse::Path::Role::Path')) { return $arg->clone; } |
|
0
|
|
|
|
|
0
|
|
29
|
0
|
|
|
|
|
0
|
else { $opts{path} = "$arg"; } |
30
|
|
|
|
|
|
|
} |
31
|
0
|
|
|
|
|
0
|
elsif (ref $arg eq 'ARRAY') { %opts = @$arg; } |
32
|
0
|
|
|
|
|
0
|
elsif (ref $arg eq 'HASH') { %opts = %$arg; } |
33
|
0
|
|
|
|
|
0
|
else { $opts{path} = $arg; } |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
# NOTE: if @_ == 0, it gets passed to DZIL and fails with its own path attr error |
36
|
80
|
|
|
|
|
320
|
else { %opts = @_; } |
37
|
|
|
|
|
|
|
|
38
|
80
|
|
100
|
|
|
363
|
my $style = delete $opts{style} // 'DZIL'; |
39
|
80
|
50
|
|
|
|
428
|
$style = "Parse::Path::$style" unless ($style =~ s/^\=//); # NOTE: kill two birds with one stone |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# Load+create the path |
42
|
80
|
|
|
|
|
379
|
return use_module($style)->new(%opts); |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
42; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
__END__ |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=pod |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=encoding utf-8 |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=head1 NAME |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
Parse::Path - Parser for paths |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 SYNOPSIS |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
use v5.10; |
60
|
|
|
|
|
|
|
use Parse::Path; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
my $path = Parse::Path->new( |
63
|
|
|
|
|
|
|
path => 'gophers[0].food.count', |
64
|
|
|
|
|
|
|
style => 'DZIL', # default |
65
|
|
|
|
|
|
|
); |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
my $step = $path->shift; # { key => 'count', ... } |
68
|
|
|
|
|
|
|
say $path->as_string; |
69
|
|
|
|
|
|
|
$path->push($path, '[2]'); |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
foreach my $p (@$path) { |
72
|
|
|
|
|
|
|
say sprintf('%-6s %s --> %s', @$p{qw(type step key)}); |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=head1 DESCRIPTION |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Parse::Path is, well, a parser for paths. File paths, object paths, URLs... A path is whatever string that can be translated into |
78
|
|
|
|
|
|
|
hashE<sol>array keys. Unlike modules like L<File::Spec> or L<File::Basename>, which are designed for interacting with file systems paths in |
79
|
|
|
|
|
|
|
a portable manner, Parse::Path is designed for interacting with I<any> path, filesystem or otherwise, at the lowest level possible. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Paths are split out into steps. Internally, these are stored as "step hashes". However, there is some exposure to these hashes as |
82
|
|
|
|
|
|
|
both input and output, so we'll describe them here: |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
{ |
85
|
|
|
|
|
|
|
type => 'HASH', # must be either HASH or ARRAY |
86
|
|
|
|
|
|
|
key => 'foo bar', # as it would be represented as a key |
87
|
|
|
|
|
|
|
step => '"foo bar"', # as it would be represented in a path |
88
|
|
|
|
|
|
|
pos => 'X+1', # used to determine depth |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
For the purposes of this manual, a "step" is usually referring to a step hash, unless specified. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
my $path = Parse::Path->new( |
96
|
|
|
|
|
|
|
path => $path, # required |
97
|
|
|
|
|
|
|
style => 'DZIL', # default |
98
|
|
|
|
|
|
|
); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
Creates a new path object. Parse::Path is really just a dispatcher to other Parse::Path modules, but it serves as a common API for |
101
|
|
|
|
|
|
|
all of them. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
Accepts the following arguments: |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=head2 path |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
path => 'gophers[0].food.count' |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
String used to create path. Can also be another Parse::Path object, a step, an array of step hashes, an array of paths, or whatever |
110
|
|
|
|
|
|
|
makes sense. |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
This parameter is required. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head2 style |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
style => 'File::Unix' |
117
|
|
|
|
|
|
|
style => '=MyApp::Parse::Path::Foobar' |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Class used to create the new path object. With a C<<< = >>> prefix, it will use that as the full class. Otherwise, the class will be |
120
|
|
|
|
|
|
|
intepreted as C<<< Parse::Path::$class >>>. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
Default is L<DZIL|Parse::Path::DZIL>. |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=head2 auto_normalize |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
auto_normalize => 1 |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
my $will_normalize = $path->auto_normalize; |
129
|
|
|
|
|
|
|
$path->auto_normalize(1); |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
If on, calls L</normalize> after any new step has been added (ie: L<new|/CONSTRUCTOR>, L</unshift>, L</push>, L</splice>). |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
Default is off. This attribute is read-write. |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=head2 auto_cleanup |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
auto_cleanup => 1 |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
my $will_cleanup = $path->auto_cleanup; |
140
|
|
|
|
|
|
|
$path->auto_cleanup(1); |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
If on, calls L</cleanup> after any new step has been added (ie: L<new|/CONSTRUCTOR>, L</unshift>, L</push>, L</splice>). |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
Default is off. This attribute is read-write. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=head1 METHODS |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=head2 step_count |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
my $count = $path->step_count; |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
Returns the number of steps in the path. Unlike L</depth>, negative-seeking steps (like C<<< .. >>> for most file-based paths) will not lower |
153
|
|
|
|
|
|
|
the step count. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=head2 depth |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
my $depth = $path->depth; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
Returns path depth. In most cases, this is the number of steps to the path, a la L</step_count>. However, relative paths might make |
160
|
|
|
|
|
|
|
this lower, or even negative. For example: |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
my $path = Parse::Path->new( |
163
|
|
|
|
|
|
|
path => '../../../foo/bar.txt', |
164
|
|
|
|
|
|
|
path_style => 'File::Unix', |
165
|
|
|
|
|
|
|
); |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
say $path->step_count; # 5 |
168
|
|
|
|
|
|
|
say $path->depth; # -1 |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
Despite the similarity to the pos value of a step hash, this method doesn't tell you whether it's relative or absolute. Use |
171
|
|
|
|
|
|
|
L</is_absolute> for that. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=head2 is_absolute |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
my $is_absolute = $path->is_absolute; |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
Returns a true value if this path is absolute. Hint: most paths are relative. For example, if the following paths were |
178
|
|
|
|
|
|
|
L<File::Unix|Parse::Path::File::Unix> paths: |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
foo/bar.txt # relative |
181
|
|
|
|
|
|
|
../bar.txt # relative |
182
|
|
|
|
|
|
|
bar.txt # relative |
183
|
|
|
|
|
|
|
/home/foo/bar.txt # absolute |
184
|
|
|
|
|
|
|
/home/../bar.txt # absolute (even prior to cleanup) |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=head2 as_string |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
my $path_str = $path->as_string; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
Returns the string form of the path. This involves taking the individual step strings of the path and placing the delimiters in the |
191
|
|
|
|
|
|
|
right place. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=head2 as_array |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
my $step_hashes = $path->as_array; |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Returns the full path as an arrayref of step hashes. The steps are cloned for integrity. If you want a simplier representation of |
198
|
|
|
|
|
|
|
the path, consider L</as_string>. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head2 shift |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
my $step_hash = $path->shift; |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
Works just like the Perl version. Removes a step from the beginning of the path and returns it. The step is cloned for integrity. |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head2 pop |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
my $step_hash = $path->pop; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
Works just like the Perl version. Removes a step from the end of the path and returns it. The step is cloned for integrity. |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=head2 unshift |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
my $count = $path->unshift($step_or_path); |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
Works just like the Perl version. Adds a step (or other path-like thingy) to the beginning of the path and returns the number of new |
217
|
|
|
|
|
|
|
steps prepended. Will also call L</cleanup> afterwards, if L</auto_cleanup> is enabled. |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=head2 push |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
my $count = $path->push($step_or_path); |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
Works just like the Perl version. Adds a step (or other path-like thingy) to the end of the path and returns the number of new steps |
224
|
|
|
|
|
|
|
appended. Will also call L</cleanup> afterwards, if L</auto_cleanup> is enabled. |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head2 splice |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
my @step_hashes = $path->splice($offset, $length, $step_or_path); |
229
|
|
|
|
|
|
|
my @step_hashes = $path->splice($offset, $length); |
230
|
|
|
|
|
|
|
my @step_hashes = $path->splice($offset); |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
my $last_step_hash = $path->splice($offset); |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
Works just like the Perl version. Removes elements designated by the offset and length, and replaces them with the new stepE<sol>path. |
235
|
|
|
|
|
|
|
The steps are cloned for integrity. Returns the steps removed in list context, or the last step removed in scalar context. Will |
236
|
|
|
|
|
|
|
also call L</cleanup> afterwards, if L</auto_cleanup> is enabled. |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=head2 clear |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
$path->clear; |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
Clears out the path. |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
Returns itself for chaining. |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=head2 replace |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
$path->replace; |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
Replaces the path with a new one. Basically just sugar for L</clear> + L</push>. Unlike the argument form of L</clone>, this retains the |
251
|
|
|
|
|
|
|
same object and just replaces the internal path. |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Returns the number of new steps created. |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=head2 clone |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
my $same_path = $path->clone; |
258
|
|
|
|
|
|
|
my $similar_path = $path->clone($new_path); |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Clones the path object and returns it. |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Optionally takes another path (object or string or whatever) and puts that path into the clone. This is handy if you want to use the |
263
|
|
|
|
|
|
|
same options and class, but just want a different path. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=head2 normalize |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
$path->normalize; |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
Normalizes the steps in the path. This ensures that the keys of the step hash and the steps will be the same thing. Or to put it |
270
|
|
|
|
|
|
|
another way, this will make a "round trip" of string-to-path-to-string work commutatively. For example, if the following paths were |
271
|
|
|
|
|
|
|
L<DZIL|Parse::Path::DZIL> paths: |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
'"Oh, but it can..." said the spider'.[0].value # Before normalize |
274
|
|
|
|
|
|
|
"\"Oh, but it can...\" said the spider"[0].value # After normalize |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
a.b...c[0].""."".'' # Before normalize |
277
|
|
|
|
|
|
|
a.b.""."".c[0]."".""."" # After normalize |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
Returns itself for chaining. |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=head2 cleanup |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
$path->cleanup; |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
Cleans up the path. Think of this in terms of C<<< cleanup >>> within L<Path::Class>. This will remove unnecessary relative steps, and |
286
|
|
|
|
|
|
|
try as best as possible to present an absolute path, or at least one that progresses in a sequential manner. For example, if the |
287
|
|
|
|
|
|
|
following paths were L<File::Unix|Parse::Path::File::Unix> paths: |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
/foo/baz/../foo.txt # /foo/foo.txt |
290
|
|
|
|
|
|
|
/foo//baz/./foo.txt # /foo/baz/foo.txt |
291
|
|
|
|
|
|
|
../../foo/../bar.txt # ../../bar.txt |
292
|
|
|
|
|
|
|
./command # command |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
Returns itself for chaining. |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=head1 UTILITY METHODS |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
These step conversion methods are available to use, but are somewhat internal, so they might be subject to change. In most cases, |
299
|
|
|
|
|
|
|
you can use the more public methods to achieve the same goals. |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=head2 key2hash |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
my $step_hash = $path->key2hash($key, $type, $pos); |
304
|
|
|
|
|
|
|
my $step_hash = $path->key2hash($key, $type); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Figures out the missing pieces of a keyE<sol>type pair, and returns a complete four-key step hash. The L</normalize> method works by |
307
|
|
|
|
|
|
|
throwing away the existing step and using this method. |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
Since pos translation works by using both step+delimiter, and C<<< key2hash >>> doesn't have access to the delimiter, it's more accurate to |
310
|
|
|
|
|
|
|
pass the pos value than leave it out. |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=head2 path_str2array |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
my $path_array = $path->path_str2array($path_str); |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
Converts a path string into a path array (of step hashes). |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
=head2 shift_path_str |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
my $step_hash = $self->shift_path_str(\$path_str); |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Removes a step from the beginning of the path string, and returns a complete four-key step hash. This is the workhorse for most of |
323
|
|
|
|
|
|
|
Parse::Path's use cases. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
=head2 blueprint |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
my $data = $self->blueprint->{$blueprint_key}; |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
Provides access to the blueprint for parsing the path style. More informaton about what this hashref contains in the L<role |
330
|
|
|
|
|
|
|
documentation|Parse::Path::Role::Path>. |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
Cloned for sanity. Create your own Path class if you need to change the specs. |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=head1 OVERLOADS |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
In addition to its standard methods, Parse::Path also has several L<overloads|overload> that are useful: |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=head2 String Concatenation (.=) |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
$path .= 'q.r.s[1]'; |
341
|
|
|
|
|
|
|
$path .= [qw( q r s[1] )]; |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
Modifies the path by calling L</push> on the RHS thing. |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=head2 Numeric Comparisons |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
$pathA < $pathB |
348
|
|
|
|
|
|
|
$pathA <= $pathB |
349
|
|
|
|
|
|
|
$pathB > $pathA |
350
|
|
|
|
|
|
|
$pathB >= $pathA |
351
|
|
|
|
|
|
|
$pathA == $pathA |
352
|
|
|
|
|
|
|
$pathA != $pathB |
353
|
|
|
|
|
|
|
$pathA <=> $pathB |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
Uses L</depth> for the numeric comparison. Still works in cases of a non-path on one side. |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=head2 String Comparisons |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
$pathA lt $pathB |
360
|
|
|
|
|
|
|
$pathA le $pathB |
361
|
|
|
|
|
|
|
$pathB gt $pathA |
362
|
|
|
|
|
|
|
$pathB ge $pathA |
363
|
|
|
|
|
|
|
$pathA eq $pathA |
364
|
|
|
|
|
|
|
$pathA ne $pathB |
365
|
|
|
|
|
|
|
$pathA cmp $pathB |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
If both sides are P:P objects, each key of the path is compared separately until a difference is found. This effectively bypasses |
368
|
|
|
|
|
|
|
delimiters as an obstacle for path comparisons. If a step is found to be an ARRAY type on both sides, a numeric comparison (C<<< <=> >>>) is |
369
|
|
|
|
|
|
|
done. Mismatched step types are allowed (and checked with C<<< cmp >>>), so sanity check your paths if this isn't desired. |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
If either side is a non-path, this will fallback to a simple path string comparison. |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=head2 Other overloads |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
!$path # !$path->step_count (ie: does the path contain anything?) |
376
|
|
|
|
|
|
|
"$path" # $path->as_string |
377
|
|
|
|
|
|
|
0+$path # $path->depth |
378
|
|
|
|
|
|
|
$$path # $path->as_string |
379
|
|
|
|
|
|
|
@$path # @{ $path->as_array } |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
These all work pretty much as you'd expect them to. |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=head1 CONVERSION |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
Different path styles can be used with ease. Convert Unix paths to Window paths? No problem: |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
my $unix_path = Parse::Path->new( |
388
|
|
|
|
|
|
|
path => '/root/tmp/file.txt', |
389
|
|
|
|
|
|
|
style => 'File::Unix' |
390
|
|
|
|
|
|
|
); |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
my $win_path = Parse::Path->new( |
393
|
|
|
|
|
|
|
path => $unix_path, |
394
|
|
|
|
|
|
|
style => 'File::Win32', |
395
|
|
|
|
|
|
|
); |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
$win_path->as_string; # \root\tmp\file.txt |
398
|
|
|
|
|
|
|
$win_path->volume('C'); |
399
|
|
|
|
|
|
|
$win_path->as_string; # C:\root\tmp\file.txt |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
$win_path->splice(-1, 1, '..\foobar.gif'); |
402
|
|
|
|
|
|
|
$win_path->cleanup->as_string; # C:\root\foobar.gif |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
$unix_path->replace($win_path); |
405
|
|
|
|
|
|
|
$unix_path->as_string; # /root/foobar.gif |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=head1 CAVEATS |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=head2 Absolute paths and step removal |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
Steps can be removed from the path as needed, but keep in mind that L</cleanup> doesn't get called methods like L</shift>, even if |
412
|
|
|
|
|
|
|
L</auto_cleanup> is set. This doesn't make a difference on absolute paths as the depth they are given is permanent. Appending two |
413
|
|
|
|
|
|
|
absolute paths may end up cancelling each other out: |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
my $path = Parse::Path->new( |
416
|
|
|
|
|
|
|
path => '/root/tmp/file.txt', |
417
|
|
|
|
|
|
|
style => 'File::Unix', |
418
|
|
|
|
|
|
|
auto_cleanup => 1, |
419
|
|
|
|
|
|
|
); |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
$path->shift; # remove the blank root |
422
|
|
|
|
|
|
|
$path->shift; # now a dangling 'tmp/file.txt', tied to position 2 |
423
|
|
|
|
|
|
|
$path->unshift('/home/bbyrd'); |
424
|
|
|
|
|
|
|
$path->as_string; # /home/tmp/file.txt |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
This problem can be sidestepped by using the string forms: |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
$path->shift; |
429
|
|
|
|
|
|
|
$path->shift; # tmp/file.txt |
430
|
|
|
|
|
|
|
$path->replace( [ '/home/bbyrd', $path->as_string ] ); |
431
|
|
|
|
|
|
|
$path->as_string; # /home/bbyrd/tmp/file.txt |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
This may be fixed in a later release. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=head2 Normalization of splits |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
While L</auto_normalize> controls normalization of steps, delimiter normalization is still automatic. For example: |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
my $path = Parse::Path->new( |
440
|
|
|
|
|
|
|
path => 'foo//////bar.txt', |
441
|
|
|
|
|
|
|
style => 'File::Unix', |
442
|
|
|
|
|
|
|
); |
443
|
|
|
|
|
|
|
say $path->as_string; # foo/bar.txt |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
This is because delimiters are not actually stored anywhere after parsing. The L</as_string> method takes the hash steps and re-adds |
446
|
|
|
|
|
|
|
the delimiters, per rules on the blueprint of the path class. (See L<Parse::Path::Role::Path/delimiter_placement>.) |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
=head2 Sparse arrays and memory usage |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
Since arrays within paths are based on indexes, there's a potential security issue with large indexes causing abnormal memory usage |
451
|
|
|
|
|
|
|
with certain modules that would use these paths. In Perl, these two arrays would have drastically different memory footprints: |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
my @small; |
454
|
|
|
|
|
|
|
$small[0] = 1; |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
my @large; |
457
|
|
|
|
|
|
|
$large[999999] = 1; |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
This can be mitigated by making sure the Path style you use will limit the total digits for array indexes. L<Parse::Path> handles |
460
|
|
|
|
|
|
|
this on all of its paths, but it's something to be aware of if you create your own path classes. |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
=head1 SEE ALSO |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
L<Data::SplitSerializer> - Uses this module for path parsing |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=head1 AVAILABILITY |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
The project homepage is L<https://github.com/SineSwiper/Parse-Path/wiki>. |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
The latest version of this module is available from the Comprehensive Perl |
471
|
|
|
|
|
|
|
Archive Network (CPAN). Visit L<http://www.perl.com/CPAN/> to find a CPAN |
472
|
|
|
|
|
|
|
site near you, or see L<https://metacpan.org/module/Parse::Path/>. |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=head1 SUPPORT |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=head2 Internet Relay Chat |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
You can get live help by using IRC ( Internet Relay Chat ). If you don't know what IRC is, |
481
|
|
|
|
|
|
|
please read this excellent guide: L<http://en.wikipedia.org/wiki/Internet_Relay_Chat>. Please |
482
|
|
|
|
|
|
|
be courteous and patient when talking to us, as we might be busy or sleeping! You can join |
483
|
|
|
|
|
|
|
those networks/channels and get help: |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=over 4 |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=item * |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
irc.perl.org |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
You can connect to the server at 'irc.perl.org' and talk to this person for help: SineSwiper. |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=back |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
=head2 Bugs / Feature Requests |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
Please report any bugs or feature requests via L<https://github.com/SineSwiper/Parse-Path/issues>. |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=head1 AUTHOR |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
Brendan Byrd <bbyrd@cpan.org> |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
This software is Copyright (c) 2013 by Brendan Byrd. |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
This is free software, licensed under: |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
The Artistic License 2.0 (GPL Compatible) |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
=cut |