[Parseperl-discuss] Documentation bug and thought
Brought to you by:
adamkennedy
From: Jeffrey G. <dr...@po...> - 2006-02-18 06:38:43
|
Patch for Document.pm - The find() member actually returns an arrayref of nodes, not a list of nodes as mentioned. find() isn't mentioned further on in the POD, so this area is the only one that needs to be patched. diff -ru output follows, along with a thought. --cut here-- --- Document.pm Fri Feb 17 22:02:49 2006 +++ Document.pm.patched Fri Feb 17 22:03:40 2006 @@ -23,7 +23,7 @@ $Document->prune('PPI::Token::Comment'); # Find all the named subroutines - my @subs = $Document->find( + my $subs = $Document->find( sub { $_[1]->isa('PPI::Statement::Sub') and $_[1]->name } ); --cut here-- And now for the thought. C<find()> is great at what it does, and can easily handle the task I've set before it, but here's the situation. I'm parsing code like: --cut here-- if(level_1()) { if(level_2()) { } else { } else { } --cut here-- and I want to collect the if() and else{} blocks at the top level, without having the find() function descend into the if(){} block as I want to process those nodes specially later. According to the find() docs I can stop it from descending into the subtrees by returning undef, but this also causes the if() node I was interested in to not be collected in the output. This can, of course, be mitigated by something like: --cut here-- my @outside_var=(); $doc->find(sub{$_[1]->isa('PPI::Token::Word') and $_[1]->content =~ /^if|else$/ and push @outside_var,$_[1]; return undef;}); --cut here-- And so on. However, note that we're throwing away the output from find() because it's all getting collected into @outside_var, and we have to use a closure because find() won't accept a reference and pass it along to the subroutine. Of course, we can still create a reasonably generic packaging function like this: --cut here-- sub branch_walker { my $collection = shift; return sub { $_[1]->isa('PPI::Token::Word') and $_[1]->content =~ /^if|else$/ and push @$collection,$_[1]; return undef } } my @outside_var=(); $doc->find(branch_walker->(\@outside_var)); --cut here-- But that sort of circumlocution is unnecessary, when we can just pass our collection variable in to C<find()> as an optional second parameter, which passes the collection variable along to our finder subroutine in $_[2]. --cut here-- my @collection = (); $doc->walk(sub{ $_[1]->isa('PPI::Token::Word') and $_[1]->content =~ /^if|else$/ and do { push @$_[2],$_[1]; return undef }; return 1; }); --cut here-- I suspect, however, that the notion of C<walk()> either violates the DOM spirit, which I can certainly understand, or it's just somewhere else in the documentation. Comments? Thoughts? -- Jeff Goff <dr...@po...> |