Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / Tree / Simple / Visitor / FindByNodeValue.pm
1
2 package Tree::Simple::Visitor::FindByNodeValue;
3
4 use strict;
5 use warnings;
6
7 our $VERSION = '0.02';
8
9 use Scalar::Util qw(blessed);
10
11 use base qw(Tree::Simple::Visitor);
12
13 sub new {
14     my ($_class) = @_;
15     my $class = ref($_class) || $_class;
16     my $visitor = {};
17     bless($visitor, $class);
18     $visitor->_init();
19     return $visitor;
20 }
21
22 sub _init {
23     my ($self) = @_;
24     $self->{success} = 0;    
25     $self->{node_value_to_find} = undef;
26     $self->SUPER::_init();
27 }
28
29 sub searchForNodeValue {
30     my ($self, $node_value) = @_;
31     (defined($node_value)) || die "Insufficient Arguments : You must provide a node value to search for";
32     $self->{node_value_to_find} = $node_value;
33 }
34
35 sub setTraversalMethod {
36         my ($self, $visitor) = @_;
37         (blessed($visitor) && $visitor->isa("Tree::Simple::Visitor"))
38                 || die "Insufficient Arguments : You must supply a valid Tree::Simple::Visitor object";
39     $self->{traversal_method} = $visitor;
40 }
41
42 sub visit {
43         my ($self, $tree) = @_;
44         (blessed($tree) && $tree->isa("Tree::Simple"))
45                 || die "Insufficient Arguments : You must supply a valid Tree::Simple object";
46
47     # reset our success flag
48     $self->{success} = 0;
49
50     my $node_value = $self->{node_value_to_find};
51     (defined($node_value)) || die "Illegal Operation : You cannot search for a node_value without setting one first";        
52     # create our filter function
53     # NOTE:
54     # in order to get an immediate exit 
55     # from the traversal once a match is
56     # found, we use 'die'. It is a somewhat
57     # unorthodox way of using this, but it
58     # works. The found tree is propogated 
59     # up the call chain and returned from 
60     # this function.
61         my $func;
62     if ($self->{_filter_function}) {
63         $func = sub { 
64             my ($tree, $test) = @_;
65             (($tree->getNodeValue() eq $node_value) &&  $self->{_filter_function}->($tree)) && die $tree;
66             };    
67     }
68     else {
69         $func = sub { 
70             my ($tree, $test) = @_;
71             ($tree->getNodeValue() eq $node_value) && die $tree;
72             };  
73     }
74
75     # we eval this so we can catch the tree
76     # match when it is thrown with 'die'
77     eval {
78         unless (defined($self->{traversal_method})) {
79             # include the trunk in our 
80             # search if needed
81             $func->($tree) if $self->includeTrunk();        
82             # and traverse
83             $tree->traverse($func);
84         }
85         else {
86             # include the trunk in our 
87             # search if needed
88             $self->{traversal_method}->includeTrunk(1) if $self->includeTrunk();
89             # and visit            
90             $self->{traversal_method}->setNodeFilter($func);
91             $self->{traversal_method}->visit($tree);
92         }  
93     };
94     # now see what we have ...
95     if ($@) {
96         # if we caught a Tree::Simple object
97         # then we have found a match, and ...
98         if (blessed($@) && $@->isa('Tree::Simple')) {
99             # we assign it to our results
100             $self->setResults($@);
101             $self->{success} = 1;
102         }
103         # however, if it is not a Tree::Simple
104         # object then it is likely a real exception
105         else {
106             # so we re-throw it
107             die $@;
108         }
109     }
110     else {
111         # if no exception is thrown though, 
112         # we failed in our search, and so we 
113         # set our success flag to false
114         $self->{success} = 0;
115     }
116 }
117
118 sub getResult {
119     my ($self) = @_;
120     # if we did not succeed, then 
121     # we return undef, ...
122     return undef unless $self->{success};
123     # otherwise we return the results
124     return $self->getResults()->[0];
125 }
126
127 1;
128
129 __END__
130
131 =head1 NAME
132
133 Tree::Simple::Visitor::FindByNodeValue - A Visitor for finding an element in a Tree::Simple hierarchy by node value
134
135 =head1 SYNOPSIS
136
137   use Tree::Simple::Visitor::FindByNodeValue;
138   
139   # create a visitor object
140   my $visitor = Tree::Simple::Visitor::FindByNodeValue->new();
141   
142   # set the search path for our tree  
143   $visitor->searchForNodeValue("My Tree Node");
144   
145   # pass the visitor to a tree
146   $tree->accept($visitor);
147   
148   # fetch the result, which will 
149   # be the Tree::Simple object that 
150   # we have found, or undefined
151   my $result = $visitor->getResult() || die "No Tree found";
152
153 =head1 DESCRIPTION
154
155 Given a node value and Tree::Simple hierarchy, this Visitor will attempt to find the node with the same node value. 
156
157 =head1 METHODS
158
159 =over 4
160
161 =item B<new>
162
163 There are no arguments to the constructor the object will be in its default state. You can use the C<setNodeFilter>, C<setTraversalMethod>, C<includeTrunk> and C<searchForNodeValue> methods to customize its behavior.
164
165 =item B<includeTrunk ($boolean)>
166
167 Based upon the value of C<$boolean>, this will tell the visitor to include the trunk of the tree in the search as well. 
168
169 =item B<setTraversalMethod ($visitor)>
170
171 By default we will use Tree::Simple's built in depth-first (pre-order) traverse method. If however, you desire the tree to be search in a different ordering, this can be accomplished using a different traversal method, you can supply a C<$visitor> object implementing that traversal type to this method (See  B<Tree::Simple::Visitor::BreadthFirstTraversal>, B<Tree::Simple::Visitor::PreOrderTraversal> and B<Tree::Simple::Visitor::PostOrderTraversal>).
172
173 =item B<searchForNodeValue ($node_value)>
174
175 This is the node value we will attempt to find within the tree.
176
177 =item B<setNodeFilter ($filter_function)>
178
179 This 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 further check the tree nodes as they are searched and so can be used to customize search behavior. For instance, you could to check against the node value as well as some other criteria. The filter function should accept a single argument, which is the current Tree::Simple object and return either true (C<1>) on success, or false (C<0>) on failure.
180
181 =item B<visit ($tree)>
182
183 This 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.
184
185 =item B<getResult>
186
187 This method will return the tree found with the specified node value (set by the C<searchForNodeValue> method) or C<undef> if no tree is found.
188
189 =back
190
191 =head1 BUGS
192
193 None that I am aware of. Of course, if you find a bug, let me know, and I will be sure to fix it. 
194
195 =head1 CODE COVERAGE
196
197 See the B<CODE COVERAGE> section in L<Tree::Simple::VisitorFactory> for more inforamtion.
198
199 =head1 SEE ALSO
200
201 These 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.
202
203 =head1 AUTHOR
204
205 stevan little, E<lt>stevan@iinteractive.comE<gt>
206
207 =head1 COPYRIGHT AND LICENSE
208
209 Copyright 2004, 2005 by Infinity Interactive, Inc.
210
211 L<http://www.iinteractive.com>
212
213 This library is free software; you can redistribute it and/or modify
214 it under the same terms as Perl itself. 
215
216 =cut
217