1package Tree::Simple::Visitor::FindByUID; 2 3use strict; 4use warnings; 5 6our $VERSION = '0.16'; 7 8use Scalar::Util qw(blessed); 9 10use base qw(Tree::Simple::Visitor); 11 12sub new { 13 my ($_class) = @_; 14 my $class = ref($_class) || $_class; 15 my $visitor = {}; 16 bless($visitor, $class); 17 $visitor->_init(); 18 return $visitor; 19} 20 21sub _init { 22 my ($self) = @_; 23 $self->{success} = 0; 24 $self->{UID_to_find} = undef; 25 $self->SUPER::_init(); 26} 27 28sub searchForUID { 29 my ($self, $UID) = @_; 30 (defined($UID)) || die "Insufficient Arguments : You must provide a UID to search for"; 31 $self->{UID_to_find} = $UID; 32} 33 34sub setTraversalMethod { 35 my ($self, $visitor) = @_; 36 (blessed($visitor) && $visitor->isa("Tree::Simple::Visitor")) 37 || die "Insufficient Arguments : You must supply a valid Tree::Simple::Visitor object"; 38 $self->{traversal_method} = $visitor; 39} 40 41sub visit { 42 my ($self, $tree) = @_; 43 (blessed($tree) && $tree->isa("Tree::Simple")) 44 || die "Insufficient Arguments : You must supply a valid Tree::Simple object"; 45 46 # reset our success flag 47 $self->{success} = 0; 48 49 my $UID = $self->{UID_to_find}; 50 (defined($UID)) || die "Illegal Operation : You cannot search for a UID without setting one first"; 51 # create our filter function 52 # NOTE: 53 # in order to get an immediate exit 54 # from the traversal once a match is 55 # found, we use 'die'. It is a somewhat 56 # unorthodox way of using this, but it 57 # works. The found tree is propagated 58 # up the call chain and returned from 59 # this function. 60 my $func; 61 if ($self->{_filter_function}) { 62 $func = sub { 63 my ($tree, $test) = @_; 64 (($tree->getUID() eq $UID) && $self->{_filter_function}->($tree)) && die $tree; 65 }; 66 } 67 else { 68 $func = sub { 69 my ($tree, $test) = @_; 70 ($tree->getUID() eq $UID) && die $tree; 71 }; 72 } 73 74 # we eval this so we can catch the tree 75 # match when it is thrown with 'die' 76 eval { 77 unless (defined($self->{traversal_method})) { 78 # include the trunk in our 79 # search if needed 80 $func->($tree) if $self->includeTrunk(); 81 # and traverse 82 $tree->traverse($func); 83 } 84 else { 85 # include the trunk in our 86 # search if needed 87 $self->{traversal_method}->includeTrunk(1) if $self->includeTrunk(); 88 # and visit 89 $self->{traversal_method}->setNodeFilter($func); 90 $self->{traversal_method}->visit($tree); 91 } 92 }; 93 # now see what we have ... 94 if ($@) { 95 # if we caught a Tree::Simple object 96 # then we have found a match, and ... 97 if (blessed($@) && $@->isa('Tree::Simple')) { 98 # we assign it to our results 99 $self->setResults($@); 100 $self->{success} = 1; 101 } 102 # however, if it is not a Tree::Simple 103 # object then it is likely a real exception 104 else { 105 # so we re-throw it 106 die $@; 107 } 108 } 109 else { 110 # if no exception is thrown though, 111 # we failed in our search, and so we 112 # set our success flag to false 113 $self->{success} = 0; 114 } 115} 116 117sub getResult { 118 my ($self) = @_; 119 # if we did not succeed, then 120 # we return undef, ... 121 return undef unless $self->{success}; 122 # otherwise we return the results 123 return $self->getResults()->[0]; 124} 125 1261; 127 128__END__ 129 130=head1 NAME 131 132Tree::Simple::Visitor::FindByUID - A Visitor for finding an element in a Tree::Simple hierarchy by UID 133 134=head1 SYNOPSIS 135 136 use Tree::Simple::Visitor::FindByUID; 137 138 # create a visitor object 139 my $visitor = Tree::Simple::Visitor::FindByUID->new(); 140 141 # set the search path for our tree 142 $visitor->searchForUID("MyTreeUID"); 143 144 # pass the visitor to a tree 145 $tree->accept($visitor); 146 147 # fetch the result, which will 148 # be the Tree::Simple object that 149 # we have found, or undefined 150 my $result = $visitor->getResult() || die "No Tree found"; 151 152=head1 DESCRIPTION 153 154Given a UID and Tree::Simple hierarchy, this Visitor will attempt to find the node with the same UID. 155 156=head1 METHODS 157 158=over 4 159 160=item B<new> 161 162There 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. 163 164=item B<includeTrunk ($boolean)> 165 166Based upon the value of C<$boolean>, this will tell the visitor to include the trunk of the tree in the search as well. 167 168=item B<setTraversalMethod ($visitor)> 169 170By 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>). 171 172=item B<searchForUID ($UID)> 173 174This is the UID we will attempt to find within the tree. 175 176=item B<setNodeFilter ($filter_function)> 177 178This 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. 179 180=item B<visit ($tree)> 181 182This 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. 183 184=item B<getResult> 185 186This method will return the tree found with the specified UID (set by the C<searchForUID> method) or C<undef> if no tree is found. 187 188=back 189 190=head1 Repository 191 192L<https://github.com/ronsavage/Tree-Simple-VisitorFactory> 193 194=head1 SUPPORT 195 196Bugs should be reported via the CPAN bug tracker at 197 198L<https://github.com/ronsavage/Tree-Simple-VisitorFactory/issues> 199 200=head1 CODE COVERAGE 201 202See the B<CODE COVERAGE> section in L<Tree::Simple::VisitorFactory> for more information. 203 204=head1 SEE ALSO 205 206These 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. 207 208=head1 ACKNOWLEDGEMENTS 209 210=over 4 211 212=item Thanks to Vitor Mori for the idea for this Visitor. 213 214=back 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