1 2package Tree::Simple::Visitor::FindByUID; 3 4use strict; 5use warnings; 6 7our $VERSION = '0.02'; 8 9use Scalar::Util qw(blessed); 10 11use base qw(Tree::Simple::Visitor); 12 13sub 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 22sub _init { 23 my ($self) = @_; 24 $self->{success} = 0; 25 $self->{UID_to_find} = undef; 26 $self->SUPER::_init(); 27} 28 29sub searchForUID { 30 my ($self, $UID) = @_; 31 (defined($UID)) || die "Insufficient Arguments : You must provide a UID to search for"; 32 $self->{UID_to_find} = $UID; 33} 34 35sub 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 42sub 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 $UID = $self->{UID_to_find}; 51 (defined($UID)) || die "Illegal Operation : You cannot search for a UID 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->getUID() eq $UID) && $self->{_filter_function}->($tree)) && die $tree; 66 }; 67 } 68 else { 69 $func = sub { 70 my ($tree, $test) = @_; 71 ($tree->getUID() eq $UID) && 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 118sub 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 1271; 128 129__END__ 130 131=head1 NAME 132 133Tree::Simple::Visitor::FindByUID - A Visitor for finding an element in a Tree::Simple hierarchy by UID 134 135=head1 SYNOPSIS 136 137 use Tree::Simple::Visitor::FindByUID; 138 139 # create a visitor object 140 my $visitor = Tree::Simple::Visitor::FindByUID->new(); 141 142 # set the search path for our tree 143 $visitor->searchForUID("MyTreeUID"); 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 155Given a UID and Tree::Simple hierarchy, this Visitor will attempt to find the node with the same UID. 156 157=head1 METHODS 158 159=over 4 160 161=item B<new> 162 163There 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<searchForUID> methods to customize its behavior. 164 165=item B<includeTrunk ($boolean)> 166 167Based 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 171By 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<searchForUID ($UID)> 174 175This is the UID we will attempt to find within the tree. 176 177=item B<setNodeFilter ($filter_function)> 178 179This 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 UID 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 183This 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 187This method will return the tree found with the specified UID (set by the C<searchForUID> method) or C<undef> if no tree is found. 188 189=back 190 191=head1 BUGS 192 193None 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 197See the B<CODE COVERAGE> section in L<Tree::Simple::VisitorFactory> for more inforamtion. 198 199=head1 SEE ALSO 200 201These 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 ACKNOWLEDGEMENTS 204 205=over 4 206 207=item Thanks to Vitor Mori for the idea for this Visitor. 208 209=back 210 211=head1 AUTHOR 212 213stevan little, E<lt>stevan@iinteractive.comE<gt> 214 215=head1 COPYRIGHT AND LICENSE 216 217Copyright 2004, 2005 by Infinity Interactive, Inc. 218 219L<http://www.iinteractive.com> 220 221This library is free software; you can redistribute it and/or modify 222it under the same terms as Perl itself. 223 224=cut 225 226