Для разбора и форматирования кода Perl, вы должны использовать PPI
.
Это тот самый инструмент, который Perl::Critic
и Perl::Tidy
используют для совершения всех своих умений.
В этом случае я изучил код для 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;
Если некоторые из ваших субтитров призывают другие подводные лодки, то в некоторых случаях (если вы используете прототипы, или позвонив по телефону подлодки без скобок), порядок, в котором они может повлиять на то, как они интерпретируются. – tobyink
@tobyink Спасибо за комментарий.Я не использую никаких прототипов. Почему вызов subs без круглых скобок является проблемой? Не могли бы вы привести пример? –
@ HåkonHægland Скобки необязательны, если подпрограмма предварительно объявлена или импортирована. 'perl -wE 'sub foo {say" foo "; } foo'' работает, 'perl -wE 'foo; sub foo {say "foo"; } ''не делает. – ThisSuitIsBlackNot