package Devel::StackTrace::AsHTML;
use strict;
use 5.008_001;
our $VERSION = '0.15';
use Data::Dumper;
use Devel::StackTrace;
use Scalar::Util;
no warnings 'qw';
my %enc = qw( & & > > < < " " ' ' );
# NOTE: because we don't know which encoding $str is in, or even if
# $str is a wide character (decoded strings), we just leave the low
# bits, including latin-1 range and encode everything higher as HTML
# entities. I know this is NOT always correct, but should mostly work
# in case $str is encoded in utf-8 bytes or wide chars. This is a
# necessary workaround since we're rendering someone else's code which
# we can't enforce string encodings.
sub encode_html {
my $str = shift;
$str =~ s/([^\x00-\x21\x23-\x25\x28-\x3b\x3d\x3f-\xff])/$enc{$1} || '' . ord($1) . ';' /ge;
utf8::downgrade($str);
$str;
}
sub Devel::StackTrace::as_html {
__PACKAGE__->render(@_);
}
sub render {
my $class = shift;
my $trace = shift;
my %opt = @_;
my $msg = encode_html($trace->frame(0)->as_string(1));
my $out = qq{
);
# Don't use while each since Dumper confuses that
for my $idx (0 .. @args - 1) {
my $value = $args[$idx];
my $dump = $dumper->($value);
$html .= qq{
};
$html .= qq{
\$_[$idx]
};
$html .= qq{
} . encode_html($dump) . qq{
};
$html .= qq{
};
}
$html .= qq(
);
return $html;
}
sub _build_lexicals {
my($id, $lexicals) = @_;
my $ref = "lex-$id";
return '' unless keys %$lexicals;
my $html = qq(
);
# Don't use while each since Dumper confuses that
for my $var (sort keys %$lexicals) {
my $value = $lexicals->{$var};
my $dump = $dumper->($value);
$dump =~ s/^\{(.*)\}$/($1)/s if $var =~ /^\%/;
$dump =~ s/^\[(.*)\]$/($1)/s if $var =~ /^\@/;
$html .= qq{
};
$html .= qq{
} . encode_html($var) . qq{
};
$html .= qq{
} . encode_html($dump) . qq{
};
$html .= qq{
};
}
$html .= qq(
);
return $html;
}
sub _build_context {
my $frame = shift;
my $file = $frame->filename;
my $linenum = $frame->line;
my $code;
if (-f $file) {
my $start = $linenum - 3;
my $end = $linenum + 3;
$start = $start < 1 ? 1 : $start;
open my $fh, '<', $file
or die "cannot open $file:$!";
my $cur_line = 0;
while (my $line = <$fh>) {
++$cur_line;
last if $cur_line > $end;
next if $cur_line < $start;
$line =~ s|\t| |g;
my @tag = $cur_line == $linenum
? (q{}, '')
: ('', '');
$code .= sprintf(
'%s%5d: %s%s', $tag[0], $cur_line, encode_html($line),
$tag[1],
);
}
close $file;
}
return $code;
}
1;
__END__
=encoding utf-8
=for stopwords
=head1 NAME
Devel::StackTrace::AsHTML - Displays stack trace in HTML
=head1 SYNOPSIS
use Devel::StackTrace::AsHTML;
my $trace = Devel::StackTrace->new;
my $html = $trace->as_html;
=head1 DESCRIPTION
Devel::StackTrace::AsHTML adds C method to L which
displays the stack trace in beautiful HTML, with code snippet context and
function parameters. If you call it on an instance of
L, you even get to see the lexical variables
of each stack frame.
=head1 AUTHOR
Tatsuhiko Miyagawa Emiyagawa@bulknews.netE
Shawn M Moore
HTML generation code is ripped off from L written by Tokuhiro Matsuno and Kazuho Oku.
=head1 COPYRIGHT
The following copyright notice applies to all the files provided in
this distribution, including binary files, unless explicitly noted
otherwise.
Copyright 2009-2013 Tatsuhiko Miyagawa
=head1 LICENSE
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=head1 SEE ALSO
L L L
=cut