File Coverage

blib/lib/Plack/Middleware/InteractiveDebugger/HTML.pm
Criterion Covered Total %
statement 15 56 26.7
branch 0 12 0.0
condition 0 2 0.0
subroutine 5 13 38.4
pod 0 8 0.0
total 20 91 21.9


line stmt bran cond sub pod time code
1             package Plack::Middleware::InteractiveDebugger::HTML;
2 1     1   7 use strict;
  1         1  
  1         32  
3 1     1   11 use warnings;
  1         4  
  1         62  
4              
5 1     1   6 use parent qw(Exporter);
  1         1  
  1         8  
6             our @EXPORT = qw( render_full render_source encode_html );
7              
8 1     1   79 use Scalar::Util qw(refaddr);
  1         1  
  1         224  
9              
10             my $header = <
11            
12             "http://www.w3.org/TR/html4/loose.dtd">
13            
14            
15             %(title) // Plack Interactive Debugger
16            
17            
18            
19            
25            
26            
27            
28             EOF
29              
30             my $footer = <
31            
32             Brought to you by DON'T PANIC, your
33             friendly Plack powered stacktrace interpreter, inspired by Werkzeug.
34            
35            
36            
37            
38             EOF
39              
40             my $page_html = $header . <
41            

%(exception_type)

42            
43            

%(exception)

44            
45            

StackTrace (most recent call first)

46             %(summary)
47            
48            

49             This is the Copy/Paste friendly version of the stacktrace.
50            

51            
52            
53            
54            
55             The debugger caught an exception in your PSGI application. You can now
56             look at the stacktrace which led to the error.
57             If you enable JavaScript you can also use additional features such as code
58             execution and much more.
59            
60             EOF
61              
62             my $console_html = $header . <
63            

Interactive Console

64            
65             In this console you can execute Perl expressions in the context of the
66             application.
67            
68            
The Console requires JavaScript.
69             EOF
70              
71             my $summary_html = <
72            
73             StackTrace (most recent call first)
74            
    %(frames)
75            
76             EOF
77              
78             my $frame_html = <
79            
80            

File "%(filename)",

81             line %(lineno),
82             in %(function_name)
83            
%(current_line)
84            
85             EOF
86              
87             my $source_table_html = '%(source)
';
88              
89             my $source_line_html = <
90            
91             %(lineno)
92             %(code)
93            
94             EOF
95              
96 1     1   7 no warnings 'qw';
  1         2  
  1         773  
97             my %enc = qw( & & > > < < " " ' ' );
98              
99             sub encode_html {
100 0     0 0   my $str = shift;
101 0 0         $str =~ s/([^\x00-\x21\x23-\x25\x28-\x3b\x3d\x3f-\xff])/$enc{$1} || '&#' . ord($1) . ';' /ge;
  0            
102 0           utf8::downgrade($str);
103 0           $str;
104             }
105              
106             sub render {
107 0     0 0   my($html, $vars) = @_;
108 0           $html =~ s/%\((.*?)\)/$vars->{$1}/g;
109 0           $html;
110             }
111              
112             sub current_line {
113 0     0 0   my $frame = shift;
114              
115 0 0         open my $fh, "<", $frame->filename or return '';
116 0           my @lines = <$fh>;
117              
118 0           my $line = $lines[$frame->line-1];
119 0           $line =~ s/^\s+//;
120 0           $line;
121             }
122              
123             sub render_frame {
124 0     0 0   my($trace, $idx) = @_;
125              
126 0           my $frame = $trace->frame($idx);
127              
128 0 0         render $frame_html, {
129             id => refaddr($trace) . "-" . $idx,
130             filename => encode_html($frame->filename),
131             lineno => $frame->line,
132             function_name => $frame->subroutine ? encode_html($frame->subroutine) : '',
133             current_line => current_line($frame),
134             };
135             }
136              
137             sub render_line {
138 0     0 0   my($frame, $line, $lineno) = @_;
139              
140 0           my @classes = ('line');
141 0 0         push @classes, 'current' if $frame->line == $lineno;
142              
143 0           render $source_line_html, {
144             classes => join(" ", @classes),
145             lineno => $lineno,
146             code => encode_html($line),
147             };
148             }
149              
150             sub render_source {
151 0     0 0   my $frame = shift;
152              
153 0           my $source;
154              
155 0 0         open my $fh, "<", $frame->filename or return '';
156 0           my @lines = <$fh>;
157              
158 0           my $lineno = 1;
159 0           for my $line (@lines) {
160 0           $source .= render_line $frame, $line, $lineno++;
161 0           $source .= "\n";
162             }
163              
164 0           render $source_table_html, { source => $source };
165             }
166              
167             sub render_summary {
168 0     0 0   my $trace = shift;
169              
170 0           my @classes = ('traceback');
171 0 0         unless ($trace->frames) {
172 0           push @classes, 'noframe-traceback';
173             }
174              
175 0           my $out;
176 0           for my $idx (0..$trace->frame_count-1) {
177 0           $out .= '
  • ' . render_frame($trace, $idx);
  • 178             }
    179              
    180 0           render $summary_html, {
    181             classes => join(" ", @classes),
    182             frames => $out,
    183             };
    184             }
    185              
    186             sub render_full {
    187 0     0 0   my($env, $trace) = @_;
    188 0           my $msg = encode_html($trace->frame(0)->as_string(1));
    189 0   0       render $page_html, {
    190             script_name => $env->{SCRIPT_NAME},
    191             evalex => 'true',
    192             console => 'false',
    193             title => $msg,
    194             exception => $msg,
    195             exception_type => ref(($trace->frame(0)->args)[0]) || "Error",
    196             summary => render_summary($trace),
    197             plaintext => $trace->as_string,
    198             traceback_id => refaddr($trace),
    199             };
    200             }
    201              
    202             1;