Hi,

This patch changes the semantics of the checking for the Perl code
coda in Perl::Critic::Policy::CodeLayout::UseParrotCoda.  At present
the Perl code coda is checked at the end of the file if no __END__ or
__DATA__ block is present, and is checked before the __END__ or
__DATA__ block if such a block is present.  Unfortunately, this makes
the coda too far from the end of the file for vim to be able to read
it, and therefore apply its policy.  Another way of implementing this
would be to put the coda at the end of the file for all files except
for files with a __DATA__ block, in which case the coda should be
"inverted" with respect to the ordering of the emacs and vim
components and put at the start of the file just after the shebang
line (or somewhere there; the vim coda needs to be within 5 lines of
the start or end of the file to be able to be seen by vim).  __END__
blocks need to be treated a bit more specially in that __END__ blocks
are often used for pod, and if one wants the coda not to appear in the
output of perldoc then a =cut line would be required before the coda.
The attached patch implements testing for this (rather complicated)
policy.

Is this a logical and appropriate way forward, or am I complicating
the issue?  I hope not.  Anyway, if this patch gets accepted, then I
can patch all the Perl code failing this policy and we can tick off
the CAGE task.

Comments definitely welcome,

Regards,

Paul

files affected:
lib/Perl/Critic/Policy/CodeLayout/UseParrotCoda.pm
Index: lib/Perl/Critic/Policy/CodeLayout/UseParrotCoda.pm
===================================================================
--- lib/Perl/Critic/Policy/CodeLayout/UseParrotCoda.pm	(revision 14906)
+++ lib/Perl/Critic/Policy/CodeLayout/UseParrotCoda.pm	(working copy)
@@ -1,4 +1,4 @@
-# $Id#
+# $Id$
 package Perl::Critic::Policy::CodeLayout::UseParrotCoda;
 
 use strict;
@@ -31,6 +31,16 @@
 # vim: expandtab shiftwidth=4:
 END_CODA
 
+our $DATA_CODA = <<'START_CODA';
+# vim: expandtab shiftwidth=4:
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+START_CODA
+
+
 #----------------------------------------------------------------------------
 
 sub violates {
@@ -38,40 +48,82 @@
 
     my @coda_lines = split /\n/, $CODA;
 
-    my $last_node;
-    for ($last_node = $doc->last_element;
-         $last_node && @coda_lines;
-         $last_node = $last_node->previous_sibling) {
+    my $last_node = $doc->last_element;
 
-        # Skip (optional) __END__ || __DATA blocks...
-        next if ( $last_node->isa('PPI::Statement::End') );
-        next if ( $last_node->isa('PPI::Statement::Data') );
-        next if ( $last_node->isa('PPI::Token::Whitespace') );
-        last if ( !$last_node->isa('PPI::Token::Comment') );
+    # need to treat __END__ blocks carefully
+    if ( $last_node->isa('PPI::Statement::End') ) {
+        # look for a =cut, any amount of whitespace, and then the coda
+        return if ($last_node =~ m{=cut\s*\Q$CODA\E\n*\z});
+        return $self->violation( $desc, $expl, $last_node );
+    }
+    # and __DATA__ blocks...
+    elsif ( $last_node->isa('PPI::Statement::Data') ) {
+        # look for the coda at the *start* of the file, but with the vim
+        # part *before* the emacs part (this way vim will still see the
+        # settings)
+        my $comments = $doc->find('PPI::Token::Comment');
 
-        my $last_coda_line = $coda_lines[-1];
-        my $last_actual_line = $last_node->content;
-        chomp $last_actual_line;
-        last if ( $last_coda_line ne $last_actual_line );
-        pop @coda_lines;
+        return if (coda_at_start($comments));
+        return $self->violation( $desc, $expl, $doc );
     }
+    # in the other cases...
+    else {
+        for ($last_node = $doc->last_element;
+             $last_node && @coda_lines;
+             $last_node = $last_node->previous_sibling) {
+            next if ( $last_node->isa('PPI::Token::Whitespace') );
+            last if ( !$last_node->isa('PPI::Token::Comment') );
 
-    return if ( [EMAIL PROTECTED] ); # We made it through all the coda lines
-    return $self->violation( $desc, $expl, $last_node || $doc );
+            # compare the last line with the coda line
+            my $last_coda_line = $coda_lines[-1];
+            my $last_actual_line = $last_node->content;
+            chomp $last_actual_line;
+            last if ( $last_coda_line ne $last_actual_line );
+            pop @coda_lines;
+        }
+
+        return if ( [EMAIL PROTECTED] ); # We made it through all the coda lines
+        return $self->violation( $desc, $expl, $last_node || $doc );
+    }
 }
 
+# search for the DATA_CODA at the start of a file
+sub coda_at_start
+{
+    my $comments_ref = shift;
+
+    # if are no comments, return failure
+    return if ($comments_ref eq "");
+
+    # search forwards through all comment lines, removing the first
+    # element of @data_coda_lines if it equals the comment line
+    my @data_coda_lines = split /\n/, $DATA_CODA;
+    foreach my $comment ( @$comments_ref ) {
+        chomp $comment;
+
+        # if we've used up the coda, end the loop
+        last if ( [EMAIL PROTECTED] );
+
+        my $first_coda_line = $data_coda_lines[0];
+        next if ($comment ne $first_coda_line);
+
+        # if the comment matches the coda line, reduce the coda lines
+        if ($comment eq $first_coda_line) {
+            shift @data_coda_lines;
+        }
+    }
+
+    # we've searched all comments, if @data_coda_lines has length
+    # zero, return success, else failure
+    return 1 if ([EMAIL PROTECTED]);  # success
+    return;                           # failure
+}
+
 1;
 
 # How meta! We ourselves must have this coda to be a valid perl file in the
 # parrot repository...
 
-# Local Variables:
-#   mode: cperl
-#   cperl-indent-level: 4
-#   fill-column: 100
-# End:
-# vim: expandtab shiftwidth=4:
-
 __END__
 
 =head1 NAME
@@ -85,3 +137,10 @@
 whitespace and a C<__END__> or C<__DATA__> blocks.
 
 =cut
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Reply via email to