Есть ли способ получить доступ (для распечатки) к списку вспомогательных модулей с произвольной глубиной вспомогательных вызовов, предшествующих текущей позиции в сценарии Perl?
Мне нужно внести изменения в некоторые модули Perl (.pm). Рабочий процесс запускается с веб-страницы через cgi-скрипт, вводящий данные через несколько модулей / объектов, заканчивающихся модулем, в котором мне нужно использовать данные. Где-то по ходу дела данные изменились, и мне нужно выяснить, где.





Вы можете использовать Devel :: StackTrace.
use Devel::StackTrace;
my $trace = Devel::StackTrace->new;
print $trace->as_string; # like carp
Он ведет себя как след Карпа, но вы можете получить больший контроль над кадрами.
Единственная проблема заключается в том, что ссылки преобразованы в строку, и если указанное значение изменится, вы его не увидите. Тем не менее, вы можете использовать PadWalker, чтобы распечатать полные данные (хотя это было бы огромно).
Очень полезная альтернатива: perl -d:Confess script.pl от Devel :: Признаться.
звонящий может это сделать, хотя вам может потребоваться еще больше информации.
Также есть Carp::confess и Carp::cluck.
Carp::longmess сделает то, что вы хотите, и это стандартно.
use Carp qw<longmess>;
use Data::Dumper;
sub A { &B; }
sub B { &C; }
sub C { &D; }
sub D { &E; }
sub E {
# Uncomment below if you want to see the place in E
# local $Carp::CarpLevel = -1;
my $mess = longmess();
print Dumper( $mess );
}
A();
__END__
$VAR1 = ' at - line 14
main::D called at - line 12
main::C called at - line 10
main::B called at - line 8
main::A() called at - line 23
';
Я придумал эту сабвуфер (теперь с дополнительным действием благословения!)
my $stack_frame_re = qr{
^ # Beginning of line
\s* # Any number of spaces
( [\w:]+ ) # Package + sub
(?: [(] ( .*? ) [)] )? # Anything between two parens
\s+ # At least one space
called [ ] at # "called" followed by a single space
\s+ ( \S+ ) \s+ # Spaces surrounding at least one non-space character
line [ ] (\d+) # line designation
}x;
sub get_stack {
my @lines = split /\s*\n\s*/, longmess;
shift @lines;
my @frames
= map {
my ( $sub_name, $arg_str, $file, $line ) = /$stack_frame_re/;
my $ref = { sub_name => $sub_name
, args => [ map { s/^'//; s/'$//; $_ }
split /\s*,\s*/, $arg_str
]
, file => $file
, line => $line
};
bless $ref, $_[0] if @_;
$ref
}
@lines
;
return wantarray ? @frames : \@frames;
}
longmess больше не является документированной или автоматически экспортируемой функцией Carp. Однако: my $mess = carp(); будет обеспечивать аналогичное, но не идентичное поведение.
Более красивый: Devel :: PrettyTrace
use Devel::PrettyTrace;
bt;
Этот код работает без дополнительных модулей. Просто включите его там, где это необходимо.
my $i = 1;
print STDERR "Stack Trace:\n";
while ( (my @call_details = (caller($i++))) ){
print STDERR $call_details[1].":".$call_details[2]." in function ".$call_details[3]."\n";
}
изящная техника (хотя должен сказать, что давно не пробовал работать с Perl :)
Должен сказать, очень приятно! Спасибо :-)
начинать с 0, а не с 1.
Если вы не можете использовать (или хотите избежать) неосновные модули, вот простая подпрограмма, которую я придумал:
#!/usr/bin/perl
use strict;
use warnings;
sub printstack {
my ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash);
my $i = 1;
my @r;
while (@r = caller($i)) {
($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash) = @r;
print "$filename:$line $subroutine\n";
$i++;
}
}
sub i {
printstack();
}
sub h {
i;
}
sub g {
h;
}
g;
Он производит следующий вывод:
/root/_/1.pl:21 main::i
/root/_/1.pl:25 main::h
/root/_/1.pl:28 main::g
Или один лайнер:
for (my $i = 0; my @r = caller($i); $i++) { print "$r[1]:$r[2] $r[3]\n"; }
Вы можете найти документацию по вызывающему здесь.
Перемещение мой комментарий в ответ:
Установите Devel :: Признаться на правильно
cpanm Devel::Confess
Бежать с
perl -d:Confess myscript.pl
При ошибках отображается весь список стека вызовов.
Хотя это не отвечает на ваш вопрос, но может помочь вам решить вашу проблему :-) Вот интересная статья, описывающая один из способов выяснить, кто изменяет ваши переменные из Марк Доминус