Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / PPI / Find.pm
diff --git a/local-lib5/lib/perl5/PPI/Find.pm b/local-lib5/lib/perl5/PPI/Find.pm
new file mode 100644 (file)
index 0000000..cbe55e5
--- /dev/null
@@ -0,0 +1,400 @@
+package PPI::Find;
+
+=pod
+
+=head1 NAME
+
+PPI::Find - Object version of the Element->find method
+
+=head1 SYNOPSIS
+
+  # Create the Find object
+  my $Find = PPI::Find->new( \&wanted );
+  
+  # Return all matching Elements as a list
+  my @found = $Find->in( $Document );
+  
+  # Can we find any matching Elements
+  if ( $Find->any_matches($Document) ) {
+       print "Found at least one matching Element";
+  }
+  
+  # Use the object as an iterator
+  $Find->start($Document) or die "Failed to execute search";
+  while ( my $token = $Find->match ) {
+       ...
+  }
+
+=head1 DESCRIPTION
+
+PPI::Find is the primary PDOM searching class in the core PPI package.
+
+=head2 History
+
+It became quite obvious during the development of PPI that many of the
+modules that would be built on top of it were going to need large numbers
+of saved, storable or easily creatable search objects that could be
+reused a number of times.
+
+Although the internal ->find method provides a basic ability to search,
+it is by no means thorough. PPI::Find attempts to resolve this problem.
+
+=head2 Structure and Style
+
+PPI::Find provides a similar API to the popular L<File::Find::Rule>
+module for file searching, but without the ability to assemble queries.
+
+The implementation of a separate PPI::Find::Rule sub-class that does
+provide this ability is left as an exercise for the reader.
+
+=head2 The &wanted function
+
+At the core of each PPI::Find object is a "wanted" function that is
+passed a number of arguments and returns a value which controls the
+flow of the search.
+
+As the search executes, each Element will be passed to the wanted function
+in depth-first order.
+
+It will be provided with two arguments. The current Element to test as $_[0],
+and the top-level Element of the search as $_[1].
+
+The &wanted function is expected to return 1 (positive) if the Element
+matches the condition, 0 (false) if it does not, and undef (undefined) if
+the condition does not match, and the Find search should not descend to
+any of the current Element's children.
+
+Errors should be reported from the &wanted function via die, which will be
+caught by the Find object and returned as an error.
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use Params::Util qw{_INSTANCE};
+
+use vars qw{$VERSION};
+BEGIN {
+       $VERSION = '1.206';
+}
+
+
+
+
+
+#####################################################################
+# Constructor
+
+=pod
+
+=head2 new &wanted
+
+The C<new> constructor takes a single argument of the &wanted function,
+as described above and creates a new search.
+
+Returns a new PPI::Find object, or C<undef> if not passed a CODE reference.
+
+=cut
+
+sub new {
+       my $class  = ref $_[0] ? ref shift : shift;
+       my $wanted = ref $_[0] eq 'CODE' ? shift : return undef;
+
+       # Create the object
+       my $self = bless {
+               wanted => $wanted,
+       }, $class;
+
+       $self;
+}
+
+=pod
+
+=head2 clone
+
+The C<clone> method creates another instance of the same Find object.
+
+The cloning is done safely, so if your existing Find object is in the
+middle of an iteration, the cloned Find object will not also be in the
+iteration and can be safely used independently.
+
+Returns a duplicate PPI::Find object.
+
+=cut
+
+sub clone {
+       my $self = ref $_[0] ? shift
+               : die "->clone can only be called as an object method";
+       my $class = ref $self;
+
+       # Create the object
+       my $clone = bless {
+               wanted => $self->{wanted},
+       }, $class;
+
+       $clone;
+}
+
+
+
+
+
+####################################################################
+# Search Execution Methods
+
+=pod
+
+=head2 in $Document [, array_ref => 1 ]
+
+The C<in> method starts and completes a full run of the search.
+
+It takes as argument a single L<PPI::Element> object which will
+serve as the top of the search process.
+
+Returns a list of PPI::Element objects that match the condition
+described by the &wanted function, or the null list on error.
+
+You should check the ->errstr method for any errors if you are
+returned the null list, which may also mean simply that no Elements
+were found that matched the condition.
+
+Because of this need to explicitly check for errors, an alternative
+return value mechanism is provide. If you pass the C<array_ref => 1>
+parameter to the method, it will return the list of matched Elements
+as a reference to an ARRAY. The method will return false if no elements
+were matched, or C<undef> on error.
+
+The ->errstr method can still be used to get the error message as normal.
+
+=cut
+
+sub in {
+       my $self    = shift;
+       my $Element = shift;
+       my %params  = @_;
+       delete $self->{errstr};
+       # Are we already acting as an iterator
+       if ( $self->{in} ) {
+               return $self->_error('->in called while another search is in progress', %params);
+       }
+
+       # Get the root element for the search
+       unless ( _INSTANCE($Element, 'PPI::Element') ) {
+               return $self->_error('->in was not passed a PPI::Element object', %params);
+       }
+
+       # Prepare the search
+       $self->{in}      = $Element;
+       $self->{matches} = [];
+
+       # Execute the search
+       eval {
+               $self->_execute;
+       };
+       if ( $@ ) {
+               my $errstr = $@;
+               $errstr =~ s/\s+at\s+line\s+.+$//;
+               return $self->_error("Error while searching: $errstr", %params);
+       }
+
+       # Clean up and return
+       delete $self->{in};
+       if ( $params{array_ref} ) {
+               if ( @{$self->{matches}} ) {
+                       return delete $self->{matches};
+               }
+               delete $self->{matches};
+               return '';
+       }
+
+       # Return as a list
+       my $matches = delete $self->{matches};
+       @$matches;
+}
+
+=pod
+
+=head2 start $Element
+
+The C<start> method lets the Find object act as an iterator. The method
+is passed the parent PPI::Element object as for the C<in> method, but does
+not accept any parameters.
+
+To simplify error handling, the entire search is done at once, with the
+results cached and provided as-requested.
+
+Returns true if the search completes, and false on error.
+
+=cut
+
+sub start {
+       my $self    = shift;
+       my $Element = shift;
+       delete $self->{errstr};
+
+       # Are we already acting as an iterator
+       if ( $self->{in} ) {
+               return $self->_error('->in called while another search is in progress');
+       }
+
+       # Get the root element for the search
+       unless ( _INSTANCE($Element, 'PPI::Element') ) {
+               return $self->_error('->in was not passed a PPI::Element object');
+       }
+
+       # Prepare the search
+       $self->{in}      = $Element;
+       $self->{matches} = [];
+
+       # Execute the search
+       eval {
+               $self->_execute;
+       };
+       if ( $@ ) {
+               my $errstr = $@;
+               $errstr =~ s/\s+at\s+line\s+.+$//;
+               $self->_error("Error while searching: $errstr");
+               return undef;
+       }
+
+       1;
+}
+
+=pod
+
+=head2 match
+
+The C<match> method returns the next matching Element in the iteration.
+
+Returns a PPI::Element object, or C<undef> if there are no remaining
+Elements to be returned.
+
+=cut
+
+sub match {
+       my $self = shift;
+       return undef unless $self->{matches};
+
+       # Fetch and return the next match
+       my $match = shift @{$self->{matches}};
+       return $match if $match;
+
+       $self->finish;
+       undef;
+}
+
+=pod
+
+=head2 finish
+
+The C<finish> method provides a mechanism to end iteration if you wish to
+stop the iteration prematurely. It resets the Find object and allows it to
+be safely reused.
+
+A Find object will be automatically finished when C<match> returns false.
+This means you should only need to call C<finnish> when you stop
+iterating early.
+
+You may safely call this method even when not iterating and it will return
+without failure.
+
+Always returns true
+
+=cut
+
+sub finish {
+       my $self = shift;
+       delete $self->{in};
+       delete $self->{matches};
+       delete $self->{errstr};
+       1;
+}
+
+
+
+
+
+#####################################################################
+# Support Methods and Error Handling
+
+sub _execute {
+       my $self   = shift;
+       my $wanted = $self->{wanted};
+       my @queue  = ( $self->{in} );
+
+       # Pull entries off the queue and hand them off to the wanted function
+       while ( my $Element = shift @queue ) {
+               my $rv = &$wanted( $Element, $self->{in} );
+
+               # Add to the matches if returns true
+               push @{$self->{matches}}, $Element if $rv;
+
+               # Continue and don't descend if it returned undef
+               # or if it doesn't have children
+               next unless defined $rv;
+               next unless $Element->isa('PPI::Node');
+
+               # Add the children to the head of the queue
+               if ( $Element->isa('PPI::Structure') ) {
+                       unshift @queue, $Element->finish if $Element->finish;
+                       unshift @queue, $Element->children;
+                       unshift @queue, $Element->start if $Element->start;
+               } else {
+                       unshift @queue, $Element->children;
+               }
+       }
+
+       1;
+}
+
+=pod
+
+=head2 errstr
+
+The C<errstr> method returns the error messages when a given PPI::Find
+object fails any action.
+
+Returns a string, or C<undef> if there is no error.
+
+=cut
+
+sub errstr {
+       shift->{errstr};
+}
+
+sub _error {
+       my $self = shift;
+       $self->{errstr} = shift;
+       my %params = @_;
+       $params{array_ref} ? undef : ();
+}
+
+1;
+
+=pod
+
+=head1 TO DO
+
+- Implement the L<PPI::Find::Rule> class
+
+=head1 SUPPORT
+
+See the L<support section|PPI/SUPPORT> in the main module.
+
+=head1 AUTHOR
+
+Adam Kennedy E<lt>adamk@cpan.orgE<gt>
+
+=head1 COPYRIGHT
+
+Copyright 2001 - 2009 Adam Kennedy.
+
+This program is free software; you can redistribute
+it and/or modify it under the same terms as Perl itself.
+
+The full text of the license can be found in the
+LICENSE file included with this module.
+
+=cut