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