Subroutines for the alphabetical sorting module

I would like to sort my module routines in alphabetical order (I have many routines, and I think it will be easier to edit the file if the routines are ordered in a file). For example, given A.pm:

package A;
use warnings;
use strict;

sub subA {
  print "A\n";
}

sub subC {
  print "C\n";
}
sub subB {
  print "B\n";
}

1;

I would like to run sortSub A.pmwhich gives:

package A;
use warnings;
use strict;

sub subA {
  print "A\n";
}
sub subB {
  print "B\n";
}
sub subC {
  print "C\n";
}
1;

Is there any CPAN resource that can help with this task?

+2
source share
2 answers

To parse and reformat Perl code, you should use PPI.

This is the same tool that Perl::Criticand Perl::Tidyuse to perform all their deeds.

PPI::Dumper, , , PPI,

, . , pod whitespace , .

use strict;
use warnings;

use PPI;
use Data::Dump;

my $src = do { local $/; <DATA> };

# Load a document
my $doc = PPI::Document->new( \$src );

# Save Sub locations for later sorting
my @group = ();
my @subs  = ();

for my $i ( 0 .. $#{ $doc->{children} } ) {
    my $child = $doc->{children}[$i];

    my ( $subtype, $subname )
        = $child->isa('PPI::Statement::Sub')
        ? grep { $_->isa('PPI::Token::Word') } @{ $child->{children} }
        : ( '', '' );

    # Look for grouped subs, whitespace and comments.  Sort each group separately.
    my $is_related = ($subtype eq 'sub') || grep { $child->isa("PPI::Token::$_") } qw(Whitespace Comment Pod);

    # State change or end of stream
    if ( my $range = $is_related .. ( !$is_related || ( $i == $#{ $doc->{children} } ) ) ) {
        if ($is_related) {
            push @group, $child;

            if ( $subtype ) {
                push @subs, { name => "$subname", children => [@group] };
                @group = ();
            }
        }

        if ( $range =~ /E/ ) {
            @group = ();

            if (@subs) {
                # Sort and Flatten
                my @sorted = map { @{ $_->{children} } } sort { $a->{name} cmp $b->{name} } @subs;

                # Assign back to document, and then reset group
                my $min_index = $i - $range + 1;
                @{ $doc->{children} }[ $min_index .. $min_index + $#sorted ] = @sorted;

                @subs = ();
            }
        }
    }
}

print $doc->serialize;

1;

__DATA__
package A;
use warnings;
use strict;

=comment
Pod describing subC
=cut
sub subC {
    print "C\n";
}

INIT {
    print "Hello World";
}

sub subB {
    print "B\n";
}

# Hello subA comment
sub subA {
    print "A\n";
}

1;

:

package A;
use warnings;
use strict;

=comment
Pod describing subC
=cut
sub subC {
    print "C\n";
}

INIT {
    print "Hello World";
}

# Hello subA comment
sub subA {
    print "A\n";
}

sub subB {
    print "B\n";
}

1;
+4

-, ;

#!/bin/sh
TOKEN=sub

gsed -e ':a;N;$!ba;s/\n/__newline__/g' "$1" > "$1.out"
gsed -i "s/__newline__\\s*$TOKEN\W/\\nsub /g" "$1.out"
sort $1.out -o $1.out
gsed -i 's/__newline__/\n/g' $1.out

: token_sort.sh myfile.pl

:

  • , __newline__
  • $TOKENS, subs,
  • unix
  • myfile.pl.out

;

  • , "# Something" "#!/usr/bin/env perl" ; , .
  • - , .
  • gnu-sed , , mac brew gnu-sed
+1

All Articles