• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /macosx-10.9.5/CPANInternal-140/Tree-Simple-VisitorFactory-0.10/lib/Tree/Simple/Visitor/
1
2package Tree::Simple::Visitor::LoadDirectoryTree;
3
4use strict;
5use warnings;
6
7our $VERSION = '0.02';
8
9use File::Spec;
10use Scalar::Util qw(blessed);
11
12use base qw(Tree::Simple::Visitor);
13
14sub new {
15    my ($_class) = @_;
16    my $class = ref($_class) || $_class;
17    my $visitor = {};
18    bless($visitor, $class);
19    $visitor->_init();
20    return $visitor;
21}
22
23sub _init {
24    my ($self) = @_;
25    $self->{sort_function} = undef;
26    $self->SUPER::_init();
27}
28
29# pre-built sort functions
30sub SORT_FILES_FIRST {
31    return sub ($$$) {
32        my ($path, $left, $right) = @_;
33        $left  = File::Spec->catdir($path, $left);
34        $right = File::Spec->catdir($path, $right);
35        return ((-d $left && -f $right) ? 1 :       # file beats directory
36                (-d $right && -f $left) ? -1 :    # file beats directory
37                    (lc($left) cmp lc($right)))     # otherwise just sort 'em
38    }
39}
40
41sub SORT_DIRS_FIRST {
42    return sub ($$$) {
43        my ($path, $left, $right) = @_;
44        $left  = File::Spec->catdir($path, $left);
45        $right = File::Spec->catdir($path, $right);
46        return ((-d $left && -f $right) ? -1 :      # directory beats file
47                (-d $right && -f $left) ? 1 :     # directory beats file
48                    (lc($left) cmp lc($right)))     # otherwise just sort 'em
49    }
50}
51
52sub setSortStyle {
53    my ($self, $sort_function) = @_;
54	(defined($sort_function) && ref($sort_function) eq "CODE")
55		|| die "Insufficient Arguments : sort function argument must be a subroutine reference";
56    $self->{sort_function} = $sort_function;
57}
58
59sub visit {
60	my ($self, $tree) = @_;
61	(blessed($tree) && $tree->isa("Tree::Simple"))
62		|| die "Insufficient Arguments : You must supply a valid Tree::Simple object";
63    # it must be a leaf
64    ($tree->isLeaf()) || die "Illegal Operation : The tree must be a leaf node to load a directory";
65    # check that our directory is valid
66    my $root_dir = $tree->getNodeValue();
67    (-e $root_dir && -d $root_dir)
68        || die "Incorrect Type : The tree's node value must be a valid directory";
69    # and load it recursively
70    $self->_recursiveLoad($tree, $root_dir);
71}
72
73sub _recursiveLoad {
74	my ($self, $t, $path) = @_;
75    # get a node filter if we have one
76    my $filter = $self->getNodeFilter();
77
78    # get the contents of the directory
79    opendir(DIR, $path) || die "IO Error : Could not open directory : $!";
80    # avoid the . and .. symbolic links
81    my @dir_contents = grep {
82                        $_ ne File::Spec->curdir() && $_ ne File::Spec->updir()
83                        } readdir(DIR);
84    close(DIR);
85
86    # sort them if we need to with full paths
87    @dir_contents = sort {
88                        $self->{sort_function}->($path, $a, $b)
89                    } @dir_contents if $self->{sort_function};
90
91    # now traverse ...
92	foreach my $item (@dir_contents) {
93        # filter based on the item name
94        $filter->($item) || next if defined($filter);
95        # get the full path for checking
96        # the item type and recursion
97        my $full_path = File::Spec->catdir($path, $item);
98		if (-d $full_path) {
99            my $new_tree = $t->new($item);
100            $t->addChild($new_tree);
101            $self->_recursiveLoad($new_tree, $full_path);
102		}
103		elsif (-f $full_path) {
104            $t->addChild($t->new($item));
105		}
106	}
107}
108
1091;
110
111__END__
112
113=head1 NAME
114
115Tree::Simple::Visitor::LoadDirectoryTree - A Visitor for loading the contents of a directory into a Tree::Simple object
116
117=head1 SYNOPSIS
118
119  use Tree::Simple::Visitor::LoadDirectoryTree;
120
121  # create a Tree::Simple object whose
122  # node is path to a directory
123  my $tree = Tree::Simple->new("./");
124
125  # create an instance of our visitor
126  my $visitor = Tree::Simple::Visitor::LoadDirectoryTree->new();
127
128  # set the directory sorting style
129  $visitor->setSortStyle($visitor->SORT_FILES_FIRST);
130
131  # create node filter to filter
132  # out certain files and directories
133  $visitor->setNodeFilter(sub {
134      my ($item) = @_;
135      return 0 if $item =~ /CVS/;
136      return 1;
137  });
138
139  # pass the visitor to a Tree::Simple object
140  $tree->accept($visitor);
141
142  # the tree now mirrors the structure of the directory
143
144=head1 DESCRIPTION
145
146This visitor can be used to load a directory tree into a Tree::Simple hierarchy.
147
148=head1 METHODS
149
150=over 4
151
152=item B<new>
153
154There are no arguments to the constructor the object will be in its default state. You can use the C<setNodeFilter> and C<setSortStyle> methods to customize its behavior.
155
156=item B<setNodeFilter ($filter_function)>
157
158This method accepts a CODE reference as its C<$filter_function> argument and throws an exception if it is not a code reference. This code reference is used to filter the tree nodes as they are created. The function is given the current directory or file being added to the tree, and it is expected to return either true (C<1>) of false (C<0>) to determine if that directory should be traversed or file added to the tree.
159
160=item B<setSortStyle ($sort_function)>
161
162This method accepts a CODE reference as its C<$sort_function> argument and throws an exception if it is not a code reference. This function is used to sort the individual levels of the directory tree right before it is added to the tree being built. The function is passed the the current path, followed by the two items being sorted. The reason for passing the path in is so that sorting operations can be performed on the entire path if desired.
163
164Two pre-built functions are supplied and described below.
165
166=over 4
167
168=item B<SORT_FILES_FIRST>
169
170This sorting function will sort files before directories, so that files are sorted alphabetically first in the list followed by directories sorted alphabetically. Here is example of how that would look:
171
172    Tree/
173        Simple.pm
174        Simple/
175            Visitor.pm
176            VisitorFactory.pm
177            Visitor/
178                PathToRoot.pm
179
180=item B<SORT_DIRS_FIRST>
181
182This sorting function will sort directories before files, so that directories are sorted alphabetically first in the list followed by files sorted alphabetically. Here is example of how that would look:
183
184    Tree/
185        Simple/
186            Visitor/
187                PathToRoot.pm
188            Visitor.pm
189            VisitorFactory.pm
190        Simple.pm
191
192=back
193
194=item B<visit ($tree)>
195
196This is the method that is used by Tree::Simple's C<accept> method. It can also be used on its own, it requires the C<$tree> argument to be a Tree::Simple object (or derived from a Tree::Simple object), and will throw and exception otherwise.
197
198The node value of the C<$tree> argument (gotten by calling C<getNodeValue>) is considered the root directory from which we begin our traversal. We use File::Spec to keep our paths cross-platform, but it is expected that you will feed in a valid path for your OS. If the path either does not exist, or is not a directory, then an exception is thrown.
199
200The C<$tree> argument which is passed to C<visit> must be a leaf node. This is because this Visitor will create all the sub-nodes for this tree. If the tree is not a leaf, an exception is thrown. We do not require the tree to be a root though, and this Visitor will not affect any nodes above the C<$tree> argument.
201
202=back
203
204=head1 BUGS
205
206None that I am aware of. Of course, if you find a bug, let me know, and I will be sure to fix it.
207
208=head1 CODE COVERAGE
209
210See the B<CODE COVERAGE> section in L<Tree::Simple::VisitorFactory> for more inforamtion.
211
212=head1 SEE ALSO
213
214These Visitor classes are all subclasses of B<Tree::Simple::Visitor>, which can be found in the B<Tree::Simple> module, you should refer to that module for more information.
215
216=head1 AUTHOR
217
218stevan little, E<lt>stevan@iinteractive.comE<gt>
219
220=head1 COPYRIGHT AND LICENSE
221
222Copyright 2004, 2005 by Infinity Interactive, Inc.
223
224L<http://www.iinteractive.com>
225
226This library is free software; you can redistribute it and/or modify
227it under the same terms as Perl itself.
228
229=cut
230
231