File Coverage

blib/lib/File/System/Object.pm
Criterion Covered Total %
statement 148 168 88.1
branch 61 72 84.7
condition 18 27 66.6
subroutine 22 25 88.0
pod 16 19 84.2
total 265 311 85.2


line stmt bran cond sub pod time code
1             package File::System::Object;
2              
3 8     8   56322 use strict;
  8         45  
  8         430  
4 8     8   43 use warnings;
  8         16  
  8         522  
5              
6             our $VERSION = '1.16';
7              
8 8     8   49 use Carp;
  8         13  
  8         585  
9 8     8   11221 use File::System::Globber;
  8         39  
  8         7010  
10              
11             =head1 NAME
12              
13             File::System::Object - Abstract class that every file system module builds upon
14              
15             =head1 DESCRIPTION
16              
17             Before reading this documentation, you should see L.
18              
19             File system modules extend this class to provide their functionality. A file system object represents a path in the file system and provides methods to locate other file system objects either relative to this object or from an absolute root.
20              
21             If you wish to write your own file system module, see the documentation below for L.
22              
23             =head2 FEATURES
24              
25             The basic idea is that every file system is comprised of objects. In general, all file systems will contain files and directories. Files are object which contain binary or textual data, while directories merely contain more files. Because any given file system might have arbitrarily many (or few) different types and the types might not always fall into the "file" or "directory" categories, the C attempts to generalize this functionality into "content" and "container".
26              
27             More advanced types might also be possible, e.g. symbolic links, devices, FIFOs, etc. However, at this time, no general solution is provided for handling these. (Individual file system modules may choose to add support for these in whatever way seems appropriate.)
28              
29             Each file system object must specify a method stating whether it contains file content and another method stating whether it may contain child files. It is possible that a given file system implementation provides both simultaneously in a single object.
30              
31             All file system objects allow for the lookup of other file system object by relative or absolute path names.
32              
33             =head2 PATH METHODS
34              
35             These methods provide the most generalized functionality provided by all objects. Each path specified to each of these must follow the rules given by the L section and may either be relative or absolute. If absolute, the operation performed will be based around the file system root. If relative, the operation performed depends on whether the object is a container or not. If a container, paths are considered relative to I object. If not a container, paths are considered relative to the I of the current object.
36              
37             =over
38              
39             =item $root = $obj-Eroot
40              
41             Return an object for the root file system.
42              
43             =item $test = $obj-Eexists($path)
44              
45             Check the given path C<$path> and determine whether a file system object exists at that path. Return a true value if there is such an object or false otherwise. If C<$path> is undefined, the method should assume C<$obj-Epath>.
46              
47             =cut
48              
49             sub exists {
50 0     0 1 0 my $self = shift;
51 0   0     0 my $path = shift || $self->path;
52              
53 0         0 return defined $self->lookup($path);
54             }
55              
56             =item $file = $obj-Elookup($path)
57              
58             Lookup the given path C<$path> and return a L reference for that path or C.
59              
60             =cut
61              
62             sub lookup {
63 0     0 1 0 my $self = shift;
64 0         0 my $path = shift;
65              
66 0         0 my $abspath = $self->normalize_path($path);
67              
68 0 0       0 if ($self->is_root) {
69 0         0 my $result = $self;
70 0         0 my @components = split m#/#, $path;
71 0         0 for my $component (@components) {
72 0 0 0     0 $self->is_container && ($result = $result->child($component))
73             or return undef;
74             }
75              
76 0         0 return $result;
77             } else {
78 0         0 return $self->root->lookup($abspath);
79             }
80             }
81              
82             =item @objs = $obj->glob($glob)
83              
84             Find all files matching the given file globs C<$glob>. The glob should be a typical csh-style file glob---see L below. Returns all matching objects. Note that globs are matched against '.' and '..', so care must be taken in crafting a glob that hopes to match files starting with '.'. (The typical solution to match all files starting with '.' is '.??*' under the assumption that one letter names are exceedingly rare and to be avoided, by the same logic.)
85              
86             =cut
87              
88             sub glob {
89 792     792 1 1575 my $self = shift;
90 792         2474 my $glob = $self->normalize_path(shift);
91              
92 792         4488 my @components = split /\//, $glob;
93 792         1247 shift @components;
94              
95 792         1362 my @open_list;
96 792         4701 my @matches = ([ $self->root->path, $self->root ]);
97              
98 792         3342 for my $component (@components) {
99 2112         5540 @open_list =
100             map {
101 2332         13194 my ($path, $obj) = @$_;
102 2112         12405 map { [ $_, $obj->lookup($_) ] } $obj->children_paths
  18216         69861  
103 2222         7267 } grep { $_->[1]->is_container } @matches;
104              
105 2222 100       9851 return () unless @open_list;
106              
107 18216         93903 @matches =
108 2090         8329 grep { $self->match_glob($component, $_->[0]) } @open_list;
109             }
110              
111 660         16956 return sort map { $_->[1] } @matches;
  726         5997  
112             }
113              
114             =item @files = $obj->find($want, @paths)
115              
116             This is similar in function to, but very different in implementation from L.
117              
118             Find all files matching or within the given paths C<@paths> or any subdirectory of those paths, which pass the criteria specifed by the C<$want> subroutine. If no C<@paths> are given, then "C<$obj>" is considered to be the path to search within.
119              
120             The C<$want> subroutine will be called once for every file found under the give paths. The C<$want> subroutine may expect a single argument, the L representing the given file. The C<$want> subroutine should return true to add the file to the returned list or false to leave the file out. The C<$want> subroutine may also set the value of C<$File::System::prune> to a true value in order to cause all contained child object to be skipped from search.
121              
122             The implementation should perform a depth first search so that children are checked immediately after their parent (unless the children are pruned, of course).
123              
124             =cut
125              
126             sub find {
127 1143     1143 1 2116 my $self = shift;
128 1143         1885 my $want = shift;
129              
130 1143 100       4653 my @dirs = @_ ? @_ : ($self);
131              
132 1143 100       2513 my @open = map { $_ = $self->lookup($_) unless ref $_; $_ } @dirs;
  1143         6526  
  1143         3805  
133              
134 1143         1820 local $File::System::prune;
135              
136 1143         1597 my @found;
137 1143         5708 while (my $file = shift @open) {
138 5069         8192 $File::System::prune = 0;
139 5069 100       15071 push @found, $file if $want->($file);
140              
141 5069 100 66     44496 unshift @open, $file->children
142             if !$File::System::prune && $file->is_container;
143             }
144              
145 1143         6178 return sort @found;
146             }
147              
148             =item $test = $obj-Eis_creatable($path, $type)
149              
150             Returns true if the user can use the C method to create an object at
151             C<$path>.
152              
153             =item $new_obj = $obj-Ecreate($path, $type)
154              
155             Attempts to create the object at the given path, C<$path> with type C<$type>. Type is a string containing one or more case-sensitive characters describing the type. Here are the meanings of the possible characters:
156              
157             =over
158              
159             =item d
160              
161             Create a container (named "d" for "directory"). This can be used alone or with the "f" flag.
162              
163             =item f
164              
165             Create a content object (named "f" for "file"). This can be used alone or with the "d" flag.
166              
167             =back
168              
169             The C method may be used first to determine if the operation is possible.
170              
171             =back
172              
173             =head2 METADATA METHODS
174              
175             These are the general methods that every L will provide.
176              
177             =over
178              
179             =item "$obj"
180              
181             The stringify operator is overloaded so that if this value is treated as a string it will take on the value of the "C" property.
182              
183             =cut
184              
185             use overload
186 38237     38237   158732 '""' => sub { shift->path },
187 8         155 'eq' => \&equals,
188             'ne' => \¬_equals,
189 8     8   134 'cmp' => \&compare;
  8         17  
190              
191             sub equals {
192 4654     4654 0 13786 my $self = shift;
193 4654         6504 my $obj = shift;
194              
195 4654 50       21095 if (UNIVERSAL::isa($obj, 'File::System::Object')) {
196 4654         19406 return $self->path eq $obj->path;
197             } else {
198 0         0 return $self->path eq $obj;
199             }
200             }
201              
202             sub not_equals {
203 0     0 0 0 my $self = shift;
204 0         0 my $obj = shift;
205              
206 0 0       0 if (UNIVERSAL::isa($obj, 'File::System::Object')) {
207 0         0 return $self->path ne $obj->path;
208             } else {
209 0         0 return $self->path ne $obj;
210             }
211             }
212              
213             sub compare {
214 2354     2354 0 3310 my $self = shift;
215 2354         3046 my $obj = shift;
216              
217 2354 50       18894 if (UNIVERSAL::isa($obj, 'File::System::Object')) {
218 2354         5112 return $self->path cmp $obj->path;
219             } else {
220 0         0 return $self->path cmp $obj;
221             }
222             }
223              
224             =item $name = $obj-Eis_valid
225              
226             This method returns whether or not the object is still valid (i.e., the object it refers to still exists).
227              
228             =item $name = $obj-Ebasename
229              
230             This is the base name of the object (local name with the rest of the path stripped out). This value is also available as C<$obj-Eget_property('basename')>. Note that the root object C should be C<'/'>. This fits better with unix, but actually differs from how Perl normally works.
231              
232             =cut
233              
234             sub basename {
235 4107     4107 1 6553 my $self = shift;
236 4107         11158 return $self->get_property('basename');
237             }
238              
239             =item $path = $obj-Edirname
240              
241             This the absolute canonical path up to but not including the base name. If the object represents the root path of the file system (i.e., F<..> = F<.>), then it is possible that C = C = C. This value is also available as C<$obj-Eget_property('dirname')>.
242              
243             =cut
244              
245             sub dirname {
246 8142     8142 1 11211 my $self = shift;
247 8142         21882 return $self->get_property('dirname');
248             }
249              
250             =item $path = $obj-Epath
251              
252             This is the absolute canonical path to the object. This value is also available as C<$obj-Eget_property('path')>.
253              
254             =cut
255              
256             sub path {
257 123962     123962 1 290312 my $self = shift;
258 123962         381832 return $self->get_property('path');
259             }
260              
261             =item $test = $obj-Eis_root
262              
263             Returns true if this file system object represents the file system root.
264              
265             =cut
266              
267             sub is_root {
268 682     682 1 1047 my $self = shift;
269 682         1451 return $self->path eq '/';
270             }
271              
272             =item $parent_obj = $obj-Eparent
273              
274             This is equivalent to:
275              
276             $parent_obj = $obj->lookup($obj->dirname);
277              
278             of you can think of it as:
279              
280             $parent_obj = $obj->lookup('..');
281              
282             This will return the file system object for the container. It will return itself if this is the root container.
283              
284             =cut
285              
286             sub parent {
287 4186     4186 1 7953 my $self = shift;
288 4186         12389 return $self->lookup($self->dirname);
289             }
290              
291             =item @keys = $obj-Eproperties
292              
293             Files may have an arbitrary set of properties associated with them. This method merely returns all the possible keys into the C method.
294              
295             =item @keys = $obj-Esettable_properties
296              
297             The keys returned by this method should be a subset of the keys returned by C. These are the modules upon which it is legal to call the C method.
298              
299             =item $value = $obj-Eget_property($key)
300              
301             Files may have an arbitrary set of properties associated with them. Many of the common accessors are just shortcuts to calling this method.
302              
303             In every implementation it must return values for at least the following keys:
304              
305             =over
306              
307             =item basename
308              
309             See C for a description. When implementing this, you may wish to use the C helper.
310              
311             =item dirname
312              
313             See C for a description. When implementing this, you may wish to use the C helper.
314              
315             =item object_type
316              
317             See C for a description.
318              
319             =item path
320              
321             See C for a description.
322              
323             =back
324              
325             =item $obj-Eset_property($key, $value)
326              
327             This sets the property given by C<$key> to the value in C<$value>. This should fail if the given key is not found in C<$key>.
328              
329             =item $obj-Erename($name)
330              
331             Renames the name of the file to the new name. This method cannot be used to move the file to a different location. See C for that.
332              
333             =item $obj-Emove($to, $force)
334              
335             Moves the file to the given path. After running, this object should refer to the file in it's new location. The C<$to> argument must be a reference to the file system container (from the same file system!) to move this object into. This method must fail if C<$obj> is a container and C<$force> isn't given or is false.
336              
337             If you move a container using the C<$force> option, and you have references to files held within that container, all of those references are probably now invalid.
338              
339             =item $copy = $obj-Ecopy($to, $force)
340              
341             Copies the file to the given path. This object should refer to the original. The object representing the copy is returned. The c<$to> argument must refer to a reference to a file system container (from the same file system!). This method must fail if C<$obj> is a container and C<$force> isn't given or is false.
342              
343             =item $obj-Eremove($force)
344              
345             Deletes the object from the file system entirely. In general, this means that the object is now completely invalid.
346              
347             The C<$force> option, when set to a true value, will remove containers and all their children and children of children, etc.
348              
349             =item $type = $obj-Eobject_type
350              
351             Synonym for:
352              
353             $type = $obj->get_property("object_type");
354              
355             The value returned is a string containing an arbitrary number of characters describing the type of the file system object. The following are defined:
356              
357             =over
358              
359             =item d
360              
361             This object may contain other files.
362              
363             =item f
364              
365             This object may have content.
366              
367             =back
368              
369             =cut
370              
371             sub object_type {
372 62671     62671 1 82180 my $self = shift;
373 62671         193434 return $self->get_property('object_type');
374             }
375              
376             =item $test = $obj-Ehas_content
377              
378             Returns a true value if the object contains file content. See L for additional methods.
379              
380             This is equivalent to:
381              
382             $obj->object_type =~ /f/;
383              
384             =cut
385              
386             sub has_content {
387 1120     1120 1 3007 my $self = shift;
388 1120         8854 return scalar $self->object_type =~ /f/;
389             }
390              
391             =item $test = $obj-Eis_container
392              
393             Returns a true value if the object may container other objects. See L for additional methods.
394              
395             This is equivalent to:
396              
397             $obj->object_type =~ /d/;
398              
399             =cut
400              
401             sub is_container {
402 61551     61551 1 312188 my $self = shift;
403 61551         163857 return scalar $self->object_type =~ /d/;
404             }
405              
406             =back
407              
408             =head2 CONTENT METHODS
409              
410             These methods are provided if C returns a true value.
411              
412             =over
413              
414             =item $test = $obj-Eis_readable
415              
416             This returns a true value if the file data can be read from---this doesn't refer to file permissions, but to actual capabilities. Can someone read the file? This literally means, "Can the file be read as a stream?"
417              
418             =item $test = $obj-Eis_seekable
419              
420             This returns a true value if the file data is available for random-access. This literally means, "Are the individual bytes of the file addressable?"
421              
422             =item $test = $obj-Eis_writable
423              
424             This returns a true value if the file data can be written to---this doesn't refer to file permissions, but to actual capabilities. Can someone write to the file? This literally means, "Can the file be overwritten?"
425              
426             I and C?>
427              
428             =item $test = $obj-Eis_appendable
429              
430             This returns a true value if the file data be appended to. This literally means, "Can the file be written to as a stream?"
431              
432             =item $fh = $obj-Eopen($access)
433              
434             Using the same permissions, C<$access>, as L, this method returns a file handle or a false value on failure.
435              
436             =item $content = $obj-Econtent
437              
438             =item @lines = $obj-Econtent
439              
440             In scalar context, this method returns the whole file in a single scalar. In list context, this method returns the whole file as an array of lines (with the newline terminator defined for the current system left intact).
441              
442             =back
443              
444             =head2 CONTAINER METHODS
445              
446             These methods are provided if C returns a true value.
447              
448             =over
449              
450             =item $test = $obj-Ehas_children
451              
452             Returns true if this container has any child objects (i.e., any child objects in addition to the mandatory '.' and '..').
453              
454             =item @paths = $obj-Echildren_paths
455              
456             Returns the relative paths of all children of the given container. The first two paths should always be '.' and '..', respectively. These two paths should be present within anything that returns true for C.
457              
458             =item @children = $obj-Echildren
459              
460             Returns the child Cs for all the actual children of this container. This is approxmiately the same as:
461              
462             @children = map { $vfs->lookup($_) } grep !/^\.\.?$/, $obj->children_paths;
463              
464             Notice that the objects for '.' and '..' are I returned.
465              
466             =item $child = $obj-Echild($name)
467              
468             Returns the child C that matches the given C<$name> or C.
469              
470             =back
471              
472             =head1 FILE SYSTEM PATHS
473              
474             Paths are noted as follows:
475              
476             =over
477              
478             =item "/"
479              
480             The "/" alone represents the ultimate root of the file system.
481              
482             =item "filename"
483              
484             File names may contain any character except the forward slash.
485              
486             The underlying file system may not be able to cope with all characters. As such, it is legal for a file system module to throw an exception if it is not able to cope with a given file name.
487              
488             Files can never have the name "." or ".." because of their special usage (see below).
489              
490             =item "filename1/filename2"
491              
492             The slash is used to indicate that "filename2" is contained within "filename1". In general, the file system module doesn't really cope with "relative" file names, as might be indicated here. However, the L does provide this functionality in a way.
493              
494             =item "."
495              
496             The single period indicates the current file. It is legal to embed multiples of these into a file path (e.g., "/./././././././" is still the root). Technically, the "." may only refer to files that may contain other files (otherwise the term makes no sense). In canonical form, all "." will be resolved by simply being removed from the path. (For example, "/./foo/./bar/./." is "/foo/bar" in canonical form.)
497              
498             The single period has another significant "feature". If a single period is placed at the start of a file name it takes on the Unix semantic of a "hidden file". Basically, all that means is that a glob wishing to match such a file must explicit start with a '.'.
499              
500             =item ".."
501              
502             The double period indicates the parent container. In the case of the root container, the root's parent is itself. In canonical form, all ".." will be resolved by replacing everything up to the ".." with the parent path. (For example, "/../foo/../bar/baz/.." is "/bar" in canonical form.)
503              
504             =item "////"
505              
506             All adjacent slashes are treated as a single slash. Thus, in canonical form, multiple adjacent slashes will be condenced into a single slash. (For example, "////foo//bar" is "/foo/bar" in canonical form.)
507              
508             =item "?"
509              
510             This character has special meaning in file globs. In a file glob it will match exactly one of any character. If you want to mean literally "?" instead, escape it with a backslash.
511              
512             =item "*"
513              
514             This character has special meaning in file globs. In a file glob it will match zero or more of any character non-greedily. If you want to mean literally "*" instead, escape it with a backslash.
515              
516             =item "{a,b,c}"
517              
518             The curly braces can be used to surround a comma separated list of alternatives in file globbing. If you mean a literal set of braces, then you need to escape them with a backslash.
519              
520             =item "[abc0-9]"
521              
522             The square brackets can be used to match any character within the given character class. If you mean a literal set of brackets, then you need to escape them with a backslash.
523              
524             =back
525              
526             =head1 MODULE AUTHORS
527              
528             If you wish to extend this interface to provide a new implementation, do so by creating a class that subclasses L. That class must then define several methods. In the process you may override any method of this object, but make sure it adheres to the interface described in the documentation.
529              
530             package My::File::Sytem::Implementation;
531              
532             use strict;
533             use warnings;
534              
535             use base qw( File::System::Object );
536              
537             # define your implementation...
538              
539             Below are lists of the methods you must or should define for your implementation. There is also a section below containing documentation for additional helper methods module authors should find useful, but general users probably won't.
540              
541             =head2 MUST DEFINE
542              
543             A subclass of L must define the following methods:
544              
545             =over
546              
547             =item root
548              
549             =item is_creatable
550              
551             =item create
552              
553             =item is_valid
554              
555             =item properties
556              
557             =item settable_properties
558              
559             =item get_property
560              
561             =item set_property
562              
563             =item rename
564              
565             =item move
566              
567             =item copy
568              
569             =item remove
570              
571             =back
572              
573             The following methods must be provided if your file system object implementation may return a true value for the C method.
574              
575             =over
576              
577             =item is_readable
578              
579             =item is_seekable
580              
581             =item is_writable
582              
583             =item is_appendable
584              
585             =item open
586              
587             =item content
588              
589             =back
590              
591             The following methods are container methods and must be defined if your file system object implementation may return true from the C method.
592              
593             =over
594              
595             =item has_children
596              
597             =item children_paths
598              
599             =item children
600              
601             =item child
602              
603             =back
604              
605             =head2 SHOULD DEFINE
606              
607             A subclass of L ought to consider defining better implementations of the following. Once all the methods above are defined correctly, these methods will work. However, they may not work efficiently.
608              
609             Any methods not listed here or in L have default implementations that are generally adequate. Also, the methods listed below in L probably shouldn't be overriden.
610              
611             =over
612              
613             =item exists
614              
615             =item glob
616              
617             =back
618              
619             =head2 HELPER METHODS
620              
621             This class also provides a few helpers that may be useful to module uathors, but probably not of much use to typical users.
622              
623             =over
624              
625             =item $clean_path = $obj-Enormalize_path($messy_path)
626              
627             This method creates a canonical path out of the given path C<$messy_path>. This is the single most important method offered to module authors. It provides several things:
628              
629             =over
630              
631             =item 1.
632              
633             If the path being canonified is relative, this method checks to see if the current object is a container. Paths are relative to the current object if the current object is container. Otherwise, the paths are relative to this object's parent.
634              
635             =item 2.
636              
637             Converts all relative paths to absolute paths.
638              
639             =item 3.
640              
641             Removes all superfluous '.' and '..' names so that it gives the most concise and direct name for the named file.
642              
643             =item 4.
644              
645             Enforces the principle that '..' applied to the root returns the root. This provides security by preventing users from getting to a file outside of the root (assuming that is possible for a given file system implementation).
646              
647             =back
648              
649             Always, always, always use this method to clean up your paths.
650              
651             =cut
652              
653             sub normalize_path {
654 123386     123386 1 192095 my $self = shift;
655 123386         187171 my $path = shift;
656              
657 123386 50       298361 defined $path
658             or croak "normalize_path must be given a path";
659              
660             # Skipped so we can still get some benefit in constructors
661 123386 100 100     755574 if (ref $self && $path !~ m#^/#) {
662             # Relative to me (I am a container) or to parent (I am not a container)
663 52295 50       168730 $self->is_container
664             or $self = $self->parent;
665              
666             # Fix us up to an absolute path
667 52295         177615 $path = $self->path."/$path";
668             }
669              
670             # Break into components
671 123386         595877 my @components = split m#/+#, $path;
672 123386 100       321520 @components = ('', '') unless @components;
673 123386 50       295472 unshift @components, '' unless @components > 1;
674              
675 123386         332525 for (my $i = 1; $i < @components;) {
676 163654 100 100     760796 if ($components[$i] eq '.') {
    100          
    100          
677 4609         15594 splice @components, $i, 1;
678             } elsif ($components[$i] eq '..' && $i == 1) {
679 1607         5938 splice @components, $i, 1;
680             } elsif ($components[$i] eq '..') {
681 2998         7760 splice @components, ($i - 1), 2;
682 2998         8346 $i--;
683             } else {
684 154440         382232 $i++;
685             }
686             }
687              
688 123386 100       280945 unshift @components, '' unless @components > 1;
689              
690 123386         620508 return join '/', @components;
691             }
692              
693             =item @matched_paths = $obj-Ematch_glob($glob, @all_paths)
694              
695             This will match the given glob pattern C<$glob> against the given paths C<@all_paths> and will return only those paths that match. This provides a de facto implementation of globbing so that any module can provide this functionality without having to invent this functionality or rely upon a third party module.
696              
697             =cut
698              
699             my $globber = File::System::Globber->new;
700              
701             sub match_glob {
702 18229     18229 1 30529 my $self = shift;
703 18229         29795 my $glob = shift;
704 18229         24495 my @tree = @{ $globber->glob($glob) };
  18229         157018  
705 18229         396921 my @paths = @_;
706              
707 18229         31390 my @matches;
708 18229         37600 MATCH: for my $str (@paths) {
709             # Special circumstance: any pattern not explicitly starting with '.'
710             # cannot match a file name starting with '.'
711 18476 100 100     148568 next if $str =~ /^\./ && $glob !~ /^\./;
712              
713 12334         22611 my $orig = $str;
714              
715 12334         21708 my @backup = ();
716 12334         30697 my $tree = [ @tree ];
717 12334         43869 while (my $el = shift @$tree) {
718 25332 100       149954 if (ref $el eq 'File::System::Glob::MatchOne') {
    100          
    100          
    100          
719 1054 100       9102 goto BACKUP unless substr $str, 0, 1, '';
720             } elsif (ref $el eq 'File::System::Glob::MatchAny') {
721 1268         3822 push @backup, [ $str, 0, @$tree ];
722             } elsif (ref $el eq 'File::System::Glob::MatchAlternative') {
723 1208         2335 my $match = 0;
724 1208         1530 for my $alt (@{ $el->{alternatives} }) {
  1208         3268  
725 2352 100       12507 if ($alt eq substr($str, 0, length($alt))) {
726 122         198 substr $str, 0, length($alt), '';
727 122         126 $match = 1;
728 122         190 last;
729             }
730             }
731              
732 1208 100       17756 goto BACKUP unless $match;
733             } elsif (ref $el eq 'File::System::Glob::MatchCollection') {
734 40         69 my $char = substr $str, 0, 1, '';
735            
736 40         45 my $match = 0;
737 40         44 for my $class (@{ $el->{classes} }) {
  40         91  
738 58 100 66     277 if ((ref $class) && ($char ge $class->[0]) && ($char le $class->[1])) {
    100 66        
739 20         29 $match = 1;
740 20         26 last;
741             } elsif ($char eq $class) {
742 18         19 $match = 1;
743 18         24 last;
744             }
745             }
746              
747 40 100       150 goto BACKUP unless $match;
748             } else {
749 21762         51261 my $char = substr $str, 0, 1, '';
750              
751 21762 100       285521 goto BACKUP unless $char eq $el->{character};
752             }
753              
754 14480 100 100     99060 next unless $str and !@$tree;
755              
756 11848         20750 BACKUP: my ($tstr, $amt, @ttree);
757 11848         16619 do {
758 12050 100       78431 next MATCH unless @backup;
759 2038         2835 ($tstr, $amt, @ttree) = @{ pop @backup };
  2038         12525  
760             } while (++$amt > length $tstr);
761              
762 1836         4262 push @backup, [ $tstr, $amt, @ttree ];
763              
764 1836         4013 $str = substr $tstr, $amt;
765 1836         8021 $tree = \@ttree;
766             }
767              
768 2322         8919 push @matches, $orig;
769             }
770              
771 18229         129121 return @matches;
772             }
773              
774             =item $basename = $obj-Ebasename_of_path($normalized_path)
775              
776             Given a normalized path, this method will return the basename for that path according to the rules employed by C. (Essentially, they are the same as L, except that the basename of "/" is "/" rather than "".)
777              
778             =cut
779              
780             sub basename_of_path {
781 5459     5459 1 7471 my $self = shift;
782 5459         8075 my $path = shift;
783              
784 5459 100       12192 if ($path eq '/') {
785 12         105 return '/';
786             } else {
787 5447         32177 my @components = split m{/}, $path;
788 5447         33621 return pop @components;
789             }
790             }
791              
792             =item $dirname = $obj-Edirname_of_path($normalized_path)
793              
794             Given a normalized path, this method will return the dirname for that path according to the rules employed by C. (These should be identical to the rules used by L as far as I know.)
795              
796             =cut
797              
798             sub dirname_of_path {
799 9724     9724 1 15264 my $self = shift;
800 9724         14422 my $path = shift;
801              
802 9724 100       20082 if ($path eq '/') {
803 108         709 return '/';
804             } else {
805 9616         35407 my @components = split m{/}, $path;
806 9616         14779 pop @components;
807 9616 100       31963 push @components, '' if @components == 1;
808 9616         110478 return join '/', @components;
809             }
810             }
811              
812             =back
813              
814             =head1 SEE ALSO
815              
816             L
817              
818             =head1 AUTHOR
819              
820             Andrew Sterling Hanenkamp, Ehanenkamp@users.sourceforge.netE
821              
822             =head1 COPYRIGHT AND LICENSE
823              
824             Copyright 2005 Andrew Sterling Hanenkamp. All Rights Reserved.
825              
826             This software is distributed and licensed under the same terms as Perl itself.
827              
828             =cut
829              
830             1