File Coverage

blib/lib/HTML/Debug.pm
Criterion Covered Total %
statement 39 119 32.7
branch 7 28 25.0
condition 3 9 33.3
subroutine 9 12 75.0
pod 3 3 100.0
total 61 171 35.6


line stmt bran cond sub pod time code
1             package HTML::Debug;
2              
3 1     1   813 use strict;
  1         2  
  1         39  
4 1     1   1550 use Data::Dumper;
  1         18895  
  1         73  
5 1     1   908 use HTML::Entities;
  1         52632  
  1         98  
6 1     1   10 use vars qw($VERSION);
  1         2  
  1         67  
7 1         11 use overload '+' => \&_add, '+=' => \&_add,
8 1     1   4 '""' => \&make;
  1         2  
9              
10             BEGIN {
11 1     1   137 eval "require DBI";
12             }
13              
14             $VERSION=0.12;
15              
16             our $AUTOLOAD;
17              
18             =head1 NAME
19              
20             HTML::Debug - Enables the output of variable and query debugging information
21             for display in HTML.
22              
23             =head1 SYNOPSIS
24              
25             use HTML::Debug;
26             my $obj = HTML::Debug->new();
27             # do some stuff with $obj here...
28              
29             =head1 DESCRIPTION
30              
31             HTML::Debug allows the developer to add variables and queries to HTML debugging
32             output. The variables and their values will be color-coded based on type. The
33             queries are displayed with their name, SQL statement, database driver,
34             database name, number of records affected, bind values, and the script name the
35             query is from. The variables are displayed in alphabetical order and the queries
36             are displayed in the order they were added to the debugging.
37              
38             This module makes use of Data::Dumper to do the hard work of displaying the
39             actual variable values. Some string manipulation is done on the output of
40             Data::Dumper, but just for aesthetic reasons.
41              
42             The + and += operators have been overloaded to emulate the add() method.
43              
44             The "" operator has also been overloaded so you can:
45             print $obj;
46             and not have to worry about the make() method.
47              
48             =head1 METHODS
49              
50             The following section documents the methods for HTML::Debug.
51              
52             =over 4
53              
54             =cut
55              
56             ########## BEGIN METHODS CODE ##########
57              
58             =pod
59              
60             =item B<$obj-Enew()>
61              
62             Creates a new HTML::Debug object. This object will hold the debugging information
63             sent to it. The new method takes one optional parameter if this parameter evaluates
64             to true, then the output will automatically be printed when the object goes out
65             of scope (or whenever the DESTROY method is called).
66              
67             Example:
68              
69             my $obj = HTML::Debug->new(); or
70              
71             my $obj = HTML::Debug->new(1);
72              
73             =cut
74              
75             sub new {
76 1     1 1 38 my $self = shift;
77 1   33     7 my $class = ref($self)||$self;
78 1         2 my $auto_output = shift;
79              
80 1 50       3 $auto_output = 0 if (not defined $auto_output);
81            
82 1         5 return bless {auto_output=>$auto_output};
83             }
84              
85             =pod
86              
87             =item B<$obj-Eadd()>
88              
89             This method adds a variable to the debugging. The first parameter is a string
90             indicating the name of the variable. The second parameter is a scalar or reference
91             to the value of the variable. For instance if you have an array, pass in \@array.
92             You may pass in any variable value including scalars, references, blessed references,
93             hashrefs, arrayrefs, typeglobs, and subroutines. Although, since Data::Dumper is used
94             for the output, passing in typeglobs and subroutines is not very useful.
95              
96             Example:
97              
98             $obj->add('myvar', $myvar);
99              
100             =cut
101              
102             sub add {
103 2     2 1 16 my $self = shift;
104 2         3 my $name;
105             my $value;
106              
107             # If only one parameter, this is an anonymous variable.
108 2 50       4 if ((@_) == 1) {
109 0         0 $self->{anon}++;
110 0         0 $name = 'VAR'.$self->{anon};
111 0         0 $value = shift;
112              
113             # Otherwise it is named.
114             } else {
115 2         3 $name = shift;
116 2         3 $value = shift;
117             # If the variable is a statement handle, do the cool query stuff instead.
118 2 50       5 if (ref $value eq 'DBI::st') {
119 0         0 return $self->_query($name, $value, @_);
120             }
121             }
122              
123             # If the variable already exists, append the new value onto an array and use the array as the value.
124 2 100       37 if (exists $self->{hVars}->{$name}) {
125 1 50       3 if (ref $self->{hVars}->{$name} eq 'ARRAY') {
126 0         0 push(@{$self->{hVars}->{$name}}, $value);
  0         0  
127             } else {
128 1         14 $self->{hVars}->{$name} = [$self->{hVars}->{$name}, $value];
129             }
130              
131             # If the variable doesn't exist, make a new entry for it.
132             } else {
133 1         5 return $self->{hVars}->{$name} = $value;
134             }
135             }
136              
137             sub _query {
138 0     0   0 my $self = shift;
139 0         0 my $name = shift;
140 0         0 my $handle = shift;
141              
142 0         0 my $hQuery = {name=>$name, st_handle=>$handle, aBindVals=>\@_, script=>$0};
143              
144             # Generate the debug text for the query on the fly as the database handle may not exist when make() is called.
145             # Output the query name, script name, rows affected, driver, database, and statement.
146 0         0 my $query = $hQuery->{st_handle};
147 0         0 my $HTMLoutput .= "
$hQuery->{name}
";
148 0         0 $HTMLoutput .= "
Query on ".$hQuery->{script}." affected ".$query->rows." row(s) from ";
149 0         0 $HTMLoutput .= $query->{Database}->{Driver}->{Name}."::".$query->{Database}->{Name}.".
";
150 0         0 $HTMLoutput .= '
'.encode_entities($query->{Statement}).'
';
151             # If bind values were provided, output those values HTML-escaped.
152 0 0       0 if (scalar @{$hQuery->{aBindVals}}) {
  0         0  
153 0         0 local $Data::Dumper::Indent = 0;
154 0         0 my $bindvals = Dumper($hQuery->{aBindVals});
155 0         0 $bindvals =~ s/^\$VAR1 = //;
156 0         0 $bindvals =~ s/;$//;
157 0         0 $HTMLoutput .= 'Bind Values:
'.encode_entities($bindvals).'


';
158             }
159 0         0 $HTMLoutput .= '';
160 0         0 $hQuery->{debug} = $HTMLoutput;
161              
162             # Store the query info in an instance variable.
163 0         0 push(@{$self->{aQueries}}, $hQuery);
  0         0  
164             }
165              
166             =pod
167              
168             =item B<$obj-Emake()>
169              
170             This method generates the HTML that represents the debugging information. It would
171             most commonly be used to print the debugging info. The variables are displayed
172             first in alphabetical order and are color-coded based on type. All hash values
173             are displayed alphabetically. In addition, the variable names are prefaced with
174             the correct sigil corresponding to their ref type.
175              
176             The queries are displayed last and are in the order that they were added to the
177             HTML::Debug object. Information displayed with each query include: the query's
178             name, the script on which it ran, the number of rows affected, the database driver
179             name, the database name, the SQL statement, and the bind values, if any.
180              
181             The variable names, variable values, SQL statements, and bind values are
182             HTML-escaped before output.
183              
184             Example:
185              
186             print $obj->make();
187              
188             =cut
189              
190             sub make {
191 0     0 1 0 my $self = shift;
192              
193             # Initalize the debugging output with a header and the server time.
194 0         0 my $HTMLoutput = "";
212              
213 0         0 $HTMLoutput .= '

Debugging Output

';
214 0         0 $HTMLoutput .= "Server time: ".localtime()."
";
215              
216             # Generate the HTML for the variables.
217 0         0 $HTMLoutput .= "

Variables

"; "; ";
218 0         0 foreach my $name (sort keys %{$self->{hVars}}) {
  0         0  
219 0         0 my $value = $self->{hVars}->{$name};
220              
221             # Determine the color and sigil of the variable based on the ref type.
222 0         0 my $type = ref $value;
223 0         0 my $color;
224             my $sigil;
225 0 0       0 if ($type eq 'HASH') {
    0          
    0          
    0          
    0          
    0          
    0          
226 0         0 $color = 'lightblue';
227 0         0 $sigil = '%';
228             } elsif ($type eq '') {
229 0         0 $color = 'white';
230 0         0 $sigil = '$';
231             } elsif ($type eq 'ARRAY') {
232 0         0 $color = 'lightgreen';
233 0         0 $sigil = '@';
234             } elsif ($type eq 'CODE') {
235 0         0 $color = 'orange';
236 0         0 $sigil = '&';
237             } elsif ($type eq 'REF') {
238 0         0 $color = 'pink';
239 0         0 $sigil = '$';
240             } elsif ($type eq 'SCALAR') {
241 0         0 $color = 'peru';
242 0         0 $sigil = '$';
243             } elsif ($type eq 'GLOB') {
244 0         0 $color = 'plum';
245 0         0 $sigil = '*';
246             } else {
247 0         0 $color = 'gray';
248 0         0 $sigil = '$';
249             }
250              
251             # Clean up the output (including HTML-escaping).
252 0         0 local $Data::Dumper::Sortkeys = 1;
253 0         0 local $Data::Dumper::Ident = 1;
254 0         0 local $Data::Dumper::Pair = '~|~|~|~|~';
255 0         0 my $output = Dumper($value);
256 0         0 $output =~ s/^\$VAR1 = //;
257 0         0 $output =~ s/;$//;
258 0         0 $output =~ s/\n /\n/g;
259 0         0 $output =~ s/\n$//;
260 0         0 $output = encode_entities($output);
261 0         0 $output =~ s/\n/
/g;
262 0         0 $output =~ s/~\|~\|~\|~\|~/ => /g;
263              
264             # Set the style attribute of the td (variable value) tag.
265 0         0 my $style = "font: 12px Arial; color: black; background: $color; border: 1px solid black;";
266              
267 0         0 $HTMLoutput .= "
$sigil$name =
268 0         0 $HTMLoutput .= "
$output
269             }
270 0         0 $HTMLoutput .= "
";
271              
272             # Generate the HTML for the queries.
273 0         0 $HTMLoutput .= "

Queries

";
274 0         0 foreach my $queryinfo (@{$self->{aQueries}}) {
  0         0  
275 0         0 $HTMLoutput .= $queryinfo->{debug};
276             }
277 0         0 $HTMLoutput .= '';
278              
279 0         0 return $HTMLoutput;
280             }
281              
282             =pod
283              
284             =item B<$obj += []>
285              
286             The + and += operators have been overloaded to support adding variables and queries to the debugging info.
287             The second argument must either be a scalar, in which case you are adding an anonymous value. Otherwise
288             it must be an arrayref. If the arrayref has two or more elements, it is treated as an ordinary variable,
289             with the first element being the name and the second being the value. If the value is a statement handle,
290             it is treated as a query with the remaining elements being the bind values.
291              
292             Examples:
293              
294             $obj += ['myvar', $value];
295              
296             $obj = $obj + ['myvar', $value];
297              
298             $obj + ['myvar', $value];
299              
300             $obj += 3; #anonymous variable
301              
302             =cut
303              
304             sub _add {
305 1     1   14 my $self = shift;
306 1         3 my $var = shift;
307              
308             # If they passed in an array of two elements or where the second element is a statement handle, then it is a named variable.
309 1 50 33     9 if ((ref $var eq 'ARRAY') and ((@$var == 2) or (ref $var->[1] eq 'DBI::st'))) {
      33        
310 1         2 my @vars = @$var;
311 1         2 my $name = shift @vars;
312 1         2 my $value = shift @vars;
313 1         4 $self->add($name, $value, @vars);
314              
315             # Otherwise, it is an unnamed variable.
316             } else {
317 0         0 $self->add($var);
318             }
319              
320 1         3 return $self;
321             }
322              
323             =pod
324              
325             =item B<$obj-Eyour_varname()>
326              
327             To make it easy to add the same variable multiple times and see all the values appended into an array, the AUTOLOAD method
328             has been implemented so you can use your variable name as a method name. For example:
329              
330             $obj->i($i);
331              
332             If inside a loop, you will see a value of $i for each cycle through the loop.
333              
334             =cut
335              
336             sub AUTOLOAD {
337 0     0     my $self = shift;
338 0           my $name = $AUTOLOAD;
339 0           $name =~ s/.*:://g;
340 0           my $value = shift;
341              
342 0           return $self->add($name, $value);
343             }
344              
345             =pod
346              
347             =item B<$obj-EDESTROY()>
348              
349             To avoid extra typing, the HTML output is printed when the object goes out of scope assuming you initalized the
350             object to do that by specifying HTML::Debug->new(1).
351              
352             =cut
353              
354             #sub DESTROY {
355             # my $self = shift;
356             # print $self->make() if ($self->{auto_output});
357             #}
358              
359             ########## END METHODS CODE ##########
360              
361             1;
362              
363             =pod
364              
365             =back
366              
367             =head1 Mason config
368              
369             Here is how you would configure HTML::Debug to work with HTML::Mason:
370              
371             In httpd.conf:
372             PerlSetVar MasonAllowGlobals $d
373              
374             In autohandler:
375             <%once>
376             use HTML::Debug;
377            
378              
379             <%init>
380             local $d = HTML::Debug->new();
381            
382              
383             <%cleanup>
384             $m->print( $d->make() );
385            
386              
387             =head1 BUGS
388              
389             Hopefully none.
390              
391             =head1 AUTHOR
392              
393             Mike Randall Erandall@ku.eduE
394              
395             =head1 MAINTAINER
396              
397             Mike Randall Erandall@ku.eduE