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