File Coverage

blib/lib/Devel/ebug/HTTP.pm
Criterion Covered Total %
statement 142 161 88.2
branch 21 38 55.2
condition 7 13 53.8
subroutine 31 32 96.8
pod 0 10 0.0
total 201 254 79.1


line stmt bran cond sub pod time code
1             package Devel::ebug::HTTP;
2              
3 1     1   948032 use strict;
  1         10  
  1         34  
4 1     1   7 use warnings;
  1         2  
  1         33  
5 1     1   27 use 5.010001;
  1         4  
6 1     1   1024 use Catalyst qw/Static::Simple/;
  1         1003484  
  1         5  
7             #use Catalyst qw/-Debug Static::Simple/;
8 1     1   13299 use File::ShareDir::Dist qw( dist_share );
  1         1160  
  1         9  
9              
10             # ABSTRACT: A web front end to a simple, extensible Perl debugger
11             our $VERSION = '0.36'; # VERSION
12              
13             # global for now, sigh
14             my $codelines_cache;
15             my $ebug;
16             my $lines_visible_above_count = 10;
17             my $sequence = 1;
18             my $vars;
19              
20             Devel::ebug::HTTP->config(
21               name => 'Devel::ebug::HTTP',
22             );
23              
24             {
25               my $share = dist_share('Devel-ebug-HTTP');
26               
27               unless(defined $share)
28               {
29                 $share = -f "share/root/index" # TODO do relative to ebug?
30                   ? "share"
31                   : die "unable to find home or root";
32               }
33              
34               Devel::ebug::HTTP->config(
35                 home => "$share",
36                 root => "$share/root",
37               );
38             }
39              
40             Devel::ebug::HTTP->setup;
41              
42             package Devel::ebug::HTTP::Controller::Root;
43              
44 1     1   802 use PPI;
  1         110402  
  1         43  
45 1     1   581 use PPI::HTML;
  1         5349  
  1         37  
46 1     1   8 use List::Util qw( max );
  1         2  
  1         68  
47 1     1   8 use base qw( Catalyst::Controller );
  1         2  
  1         167  
48              
49             BEGIN {
50 1     1   4   $INC{'Devel/ebug/HTTP/Controller/Root.pm'} = __FILE__;
51 1         12   Devel::ebug::HTTP::Controller::Root->config( namespace => '' );
52             }
53              
54             sub default : Private {
55 2     2 0 88864   my($self, $c) = @_;
56 2         17   $c->stash->{template} = 'index';
57 2         156   $c->forward('do_the_request');
58 1     1   7073 }
  1         2  
  1         8  
59              
60             sub ajax_variable : Local {
61 2     2 0 103039   my ($self, $context, $variable) = @_;
62 2 50       24   $variable = '\\' . $variable if $variable =~ /^[%@]/;
63 2         21   my $value = $ebug->yaml($variable);
64 2 50       15094   $value =~ s/^--- // unless $variable =~ /^[%@]/;
65 2 100       23   $value = "Not defined" if $value =~ /^Global symbol/;
66 2         10   $value =~ s{\n}{<br/>}g;
67 2         15   my $xml = qq{<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
68             <response>
69             <variable>$variable</variable>
70             <value><![CDATA[$value]]></value>
71             </response>
72             };
73 2         68   $context->response->content_type("text/xml");
74 2         672   $context->response->output($xml);
75 1     1   1527 }
  1         2  
  1         4  
76              
77             sub ajax_eval : Local {
78 1     1 0 30179   my ($self, $context) = @_;
79 1         24   my $eval = $context->request->parameters->{eval};
80 1   50     75   my $result = $ebug->eval($eval) || "No output";
81 1         7347   $result =~ s/ at \(eval .+$//;
82 1         33   $context->response->content_type("text/html");
83 1         319   $context->response->output($result);
84 1     1   1508 }
  1         2  
  1         5  
85              
86             sub end : Private {
87 5     5 0 7298   my($self, $c) = @_;
88 5 100       23   if ($c->stash->{template}) {
89 2         573     $c->response->content_type("text/html");
90 2         735     $c->forward('Devel::ebug::HTTP::View::TT');
91               }
92 1     1   1282 }
  1         2  
  1         5  
93              
94             sub do_the_request : Private {
95 2     2 0 1070   my($self, $c) = @_;
96 2         58   my $params = $c->request->parameters;
97              
98             # clear out template variables
99 2         136   $vars = {};
100              
101             # pass commands we've been passed to the ebug
102 2   100     25   my $action = lc($params->{myaction} || '');
103 2         29   tell_ebug($c, $action);
104              
105             # check we're doing things in the right order
106 2         15004   my $cgi_sequence = $params->{sequence};
107 2 50 66     15   if (defined $cgi_sequence && $cgi_sequence < $sequence) {
108 0         0     $ebug->undo($sequence - $cgi_sequence);
109 0         0     $sequence = $cgi_sequence;
110               }
111 2         14   $sequence++;
112              
113 2         14   set_up_stash($c);
114 1     1   1097 }
  1         2  
  1         5  
115              
116             sub tell_ebug {
117 2     2 0 8   my ($c, $action) = @_;
118 2         56   my $params = $c->request->parameters;
119               
120 2 0 33     132   if ($ebug->finished &&
      33        
121                  ($action ne "restart") &&
122                  ($action ne "undo")) {
123 0         0      return;
124               }
125              
126 2 50       40   if ($action eq 'break point:') {
    50          
    50          
127 0         0     $ebug->break_point($params->{'break_point'});
128               } elsif ($action eq 'break_point') {
129 0         0     $ebug->break_point($params->{line});
130               } elsif ($action eq 'break_point_delete') {
131 0         0     $ebug->break_point_delete($params->{line});
132 2 50       31   } if ($action eq 'next') {
    50          
    50          
    50          
133 0         0     $ebug->next;
134               } elsif ($action eq 'restart') {
135 0         0     $ebug->load;
136               } elsif ($action eq 'return') {
137 0         0     $ebug->return;
138               } elsif ($action eq 'run') {
139 0         0     $ebug->run;
140 2 100       10   } if ($action eq 'step') {
    50          
141 1         9     $ebug->step;
142               } elsif ($action eq 'undo') {
143 0         0     $ebug->undo;
144               }
145             }
146              
147             sub set_up_stash {
148 2     2 0 7   my($c) = @_;
149 2         58   my $params = $c->request->parameters;
150              
151 2         125   my $break_points;
152 2         22   $break_points->{$_}++ foreach $ebug->break_points;
153              
154 2         12619   my $url = $c->request->base;
155              
156 2         106   my($stdout, $stderr) = $ebug->output;
157              
158 2         11678   my $codelines = codelines($c);
159              
160 2         722   $vars = {
161                 %$vars,
162                 break_points => $break_points,
163                 codelines => $codelines,
164                 ebug => $ebug,
165                 sequence => $sequence,
166                 stack_trace_human => [$ebug->stack_trace_human],
167                 stdout => $stdout,
168                 stderr => $stderr,
169                 subroutine => $ebug->subroutine,
170                 top_visible_line => max(1, $ebug->line - $lines_visible_above_count + 1),
171                 url => $url,
172               };
173              
174 2         11626   foreach my $k (keys %$vars) {
175 20         1251     $c->stash->{$k} = $vars->{$k};
176               }
177             }
178              
179             sub codelines {
180 2     2 0 9   my($c) = @_;
181 2         11   my $filename = $ebug->filename;
182 2 100       26   return $codelines_cache->{$filename} if exists $codelines_cache->{$filename};
183              
184 1         75   my $url = $c->request->base;
185 1         48   my $code = join "\n", $ebug->codelines;
186 1         16241   my $document = PPI::Document->new(\$code);
187 1         15596   my $highlight = PPI::HTML->new(line_numbers => 1);
188 1         94   my $pretty = $highlight->html($document);
189              
190 1         12529   my $split = '<span class="line_number">';
191              
192             # turn significant whitespace into &nbsp;
193               my @lines = map {
194 1         47     $_ =~ s{</span>( +)}{"</span>" . ("&nbsp;" x length($1))}e;
  16         54  
  8         30  
195 16         44     "$split$_";
196               } split /$split/, $pretty;
197              
198             # right-justify the line number
199               @lines = map {
200 1         6     s{<span class="line_number"> ?(\d+) ?:}{
  16         63  
201 15         32 my $line = $1;
202 15         24 my $size = 4 - (length($1));
203 15 50       31 $size = 0 if $size < 0;
204 15         26 $line = line_html($url, $line);
205 15         60 '<span class="line_number">' . ("&nbsp;" x $size) . "$line:"}e;
206 16         41     $_;
207               } @lines;
208              
209             # add the dynamic tooltips
210               @lines = map {
211 1         4     s{<span class="symbol">(.+?)</span>}{
  16         44  
212 13         29 '<span class="symbol">' . variable_html($url, $1) . "</span>"
213             }eg;
214 16         35     $_;
215               } @lines;
216              
217             # make us slightly more XHTML
218 1         39   $_ =~ s{<br>}{<br/>} foreach @lines;
219              
220             # link module names to metacpan
221               @lines = map {
222 1         7     $_ =~ s{<span class="word">([^<]+?::[^<]+?)</span>}{<span class="word"><a href="https://metacpan.org/pod/$1">$1</a></span>};
  16         34  
223 16         32     $_;
224               } @lines;
225              
226 1         10   $codelines_cache->{$filename} = \@lines;
227 1         44   return \@lines;
228             }
229              
230             sub variable_html {
231 13     13 0 30   my($url, $variable) = @_;
232 13         67   return qq{<a href="#" style="text-decoration: none" onmouseover="return tooltip('$variable')" onmouseout="return nd();">$variable</a>};
233             }
234              
235             sub line_html {
236 15     15 0 28   my($url, $line) = @_;
237 15         34   return qq{<a href="#" style="text-decoration: none" onClick="return break_point($line)">$line</a>};
238             }
239              
240             package Devel::ebug::HTTP::View::TT;
241              
242 1     1   1947 use strict;
  1         2  
  1         42  
243 1     1   8 use warnings;
  1         2  
  1         56  
244 1     1   651 use Catalyst::View::TT;
  1         67624  
  1         44  
245 1     1   10 use base qw(Catalyst::View::TT);
  1         19  
  1         114  
246              
247             BEGIN {
248 1     1   214   $INC{'Devel/ebug/HTTP/View/TT.pm'} = __FILE__;
249             }
250              
251             package Devel::ebug::HTTP::App;
252              
253             sub main {
254 0     0   0   my $filename = shift @ARGV;
255 0 0       0   die "Usage: ebug_http filename\n" unless $filename;
256              
257 0         0   require Devel::ebug;
258 0         0   $ebug = Devel::ebug->new;
259 0         0   $ebug->program($filename);
260 0         0   $ebug->load;
261              
262 0         0   require Catalyst::ScriptRunner;
263 0         0   Catalyst::ScriptRunner->run('Devel::ebug::HTTP', 'Server');
264             }
265              
266             sub ebug {
267 1     1   1113701   my(undef, $new) = @_;
268 1 50       13   $ebug = $new if @_ > 1;
269 1         10   return $ebug;
270             }
271              
272             1;
273              
274             __END__
275            
276             =pod
277            
278             =encoding UTF-8
279            
280             =head1 NAME
281            
282             Devel::ebug::HTTP - A web front end to a simple, extensible Perl debugger
283            
284             =head1 VERSION
285            
286             version 0.36
287            
288             =head1 SYNOPSIS
289            
290             ebug_http calc.pl
291            
292             =head1 DESCRIPTION
293            
294             A debugger is a computer program that is used to debug other
295             programs. L<Devel::ebug> is a simple, extensible Perl debugger with a
296             clean API. L<Devel::ebug::HTTP> is a web-based frontend to L<Devel::ebug> which
297             presents a simple, pretty way to debug programs. L<ebug_http> is
298             the command line program to launch the debugger. It will return a URL
299             which you should point a web browser to.
300            
301             =head1 SEE ALSO
302            
303             =over 4
304            
305             =item L<Devel::ebug>
306            
307             Simple extensible Perl debugger with clean API.
308            
309             =item L<ebug_http>
310            
311             Command-line interface to ebug/http debugger.
312            
313             =item L<Devel::hdb>
314            
315             Similar web based debugger for Perl
316            
317             =back
318            
319             =head1 AUTHOR
320            
321             Original author: Leon Brocard E<lt>acme@astray.comE<gt>
322            
323             Current maintainer: Graham Ollis E<lt>plicease@cpan.orgE<gt>
324            
325             =head1 COPYRIGHT AND LICENSE
326            
327             This software is copyright (c) 2005-2021 by Leon Brocard.
328            
329             This is free software; you can redistribute it and/or modify it under
330             the same terms as the Perl 5 programming language system itself.
331            
332             =cut
333