File Coverage

blib/lib/HTML/Lint/Error.pm
Criterion Covered Total %
statement 72 73 98.6
branch 6 8 75.0
condition 10 14 71.4
subroutine 18 18 100.0
pod 10 10 100.0
total 116 123 94.3


line stmt bran cond sub pod time code
1             package HTML::Lint::Error;
2              
3 42     42   165013 use warnings;
  42         92  
  42         1064  
4 42     42   169 use strict;
  42         58  
  42         716  
5              
6 42     42   4930 use parent 'Exporter';
  42         3595  
  42         216  
7              
8             our @EXPORT_OK = qw( STRUCTURE HELPER FLUFF );
9             our %EXPORT_TAGS = ( types => [@EXPORT_OK] );
10              
11             our %errors;
12              
13             =head1 NAME
14              
15             HTML::Lint::Error - Error object for the Lint functionality
16              
17             =head1 SYNOPSIS
18              
19             See L for all the gory details.
20              
21             =head1 EXPORTS
22              
23             None. It's all object-based.
24              
25             =head1 METHODS
26              
27             Almost everything is an accessor.
28              
29             =head1 Error types: C, C, C
30              
31             Each error has a type. Note that these roughly, but not exactly, go
32             from most severe to least severe.
33              
34             =over 4
35              
36             =item * C
37              
38             For problems that relate to the structural validity of the code.
39             Examples: Unclosed tags, incorrect values for attributes, and
40             repeated attributes.
41              
42             =item * C
43              
44             Helpers are notes that will help you with your HTML, or that will help
45             the browser render the code better or faster. Example: Missing HEIGHT
46             and WIDTH attributes in an IMG tag.
47              
48             =item * C
49              
50             Fluff is for items that don't hurt your page, but don't help it either.
51             This is usually something like an unknown attribute on a tag.
52              
53             =back
54              
55             =cut
56              
57 42     42   3758 use constant CONFIG => 1;
  42         92  
  42         3445  
58 42     42   218 use constant STRUCTURE => 2;
  42         71  
  42         1657  
59 42     42   196 use constant HELPER => 3;
  42         84  
  42         1632  
60 42     42   232 use constant FLUFF => 4;
  42         71  
  42         26926  
61              
62             =head2 new()
63              
64             Create an object. It's not very exciting.
65              
66             =cut
67              
68             sub new {
69 99     99 1 269 my $class = shift;
70              
71 99         136 my $file = shift;
72 99         125 my $line = shift;
73 99         133 my $column = shift;
74 99         162 my $errcode = shift;
75 99         200 my @errparms = @_;
76              
77             # Add an element that says what tag caused the error (B, TR, etc)
78             # so that we can match 'em up down the road.
79 99         387 my $self = {
80             _file => $file,
81             _line => $line,
82             _column => $column,
83             _errcode => $errcode,
84             _errtext => undef,
85             _type => undef,
86             };
87              
88 99         181 bless $self, $class;
89              
90 99         321 $self->_expand_error( $errcode, @errparms );
91              
92 99         231 return $self;
93             }
94              
95             sub _expand_error {
96 99     99   144 my $self = shift;
97              
98 99         153 my $errcode = shift;
99              
100 99         199 my $specs = $errors{$errcode};
101 99         127 my $str;
102 99 50       182 if ( $specs ) {
103 99         169 ($str, $self->{_type}) = @{$specs};
  99         369  
104             }
105             else {
106 0         0 $str = "Unknown code: $errcode";
107             }
108              
109 99 50       208 if ( defined $str ) {
110 99         197 while ( @_ ) {
111 120         165 my $var = shift;
112 120         134 my $val = shift;
113 120         1275 $str =~ s/\$\{$var\}/$val/g;
114             }
115             }
116              
117 99         192 $self->{_errtext} = $str;
118              
119 99         163 return;
120             }
121              
122             =head2 is_type( $type1 [, $type2 ] )
123              
124             Tells if any of I<$type1>, I<$type2>... match the error's type.
125             Returns the type that matched.
126              
127             if ( $err->is_type( HTML::Lint::Error::STRUCTURE ) ) {....
128              
129             =cut
130              
131             sub is_type {
132 18     18 1 33 my $self = shift;
133              
134 18         31 for my $matcher ( @_ ) {
135 25 100       51 return $matcher if $matcher eq $self->type;
136             }
137              
138 12         38 return;
139             }
140              
141             =head2 where()
142              
143             Returns a formatted string that describes where in the file the
144             error has occurred.
145              
146             For example,
147              
148             (14:23)
149              
150             for line 14, column 23.
151              
152             The terrible thing about this function is that it's both a plain
153             ol' formatting function as in
154              
155             my $str = where( 14, 23 );
156              
157             AND it's an object method, as in:
158              
159             my $str = $error->where();
160              
161             I don't know what I was thinking when I set it up this way, but
162             it's bad practice.
163              
164             =cut
165              
166             sub where {
167 85     85 1 142 my $line;
168             my $col;
169              
170 85 100       197 if ( not ref $_[0] ) {
171 15         32 $line = shift;
172 15         20 $col = shift;
173             }
174             else {
175 70         101 my $self = shift;
176 70         123 $line = $self->line;
177 70         139 $col = $self->column;
178             }
179 85   100     177 $col ||= 0;
180 85         412 return sprintf( '(%s:%s)', $line, $col + 1 );
181             }
182              
183             =head2 as_string()
184              
185             Returns a nicely-formatted string for printing out to stdout or some similar user thing.
186              
187             =cut
188              
189             sub as_string {
190 70     70 1 1803 my $self = shift;
191              
192 70         192 return sprintf( '%s %s %s', $self->file, $self->where, $self->errtext );
193             }
194              
195             =head2 file()
196              
197             Returns the filename of the error, as set by the caller.
198              
199             =head2 line()
200              
201             Returns the line number of the error.
202              
203             =head2 column()
204              
205             Returns the column number, starting from 0
206              
207             =head2 errcode()
208              
209             Returns the HTML::Lint error code. Don't rely on this, because it will probably go away.
210              
211             =head2 errtext()
212              
213             Descriptive text of the error
214              
215             =head2 type()
216              
217             Type of the error
218              
219             =cut
220              
221 70   100 70 1 113 sub file { my $self = shift; return $self->{_file} || '' }
  70         242  
222 70   50 70 1 85 sub line { my $self = shift; return $self->{_line} || '' }
  70         155  
223 70   100 70 1 90 sub column { my $self = shift; return $self->{_column} || '' }
  70         175  
224 70   50 70 1 49549 sub errcode { my $self = shift; return $self->{_errcode} || '' }
  70         331  
225 70   50 70 1 98 sub errtext { my $self = shift; return $self->{_errtext} || '' }
  70         340  
226 25   50 25 1 27 sub type { my $self = shift; return $self->{_type} || '' }
  25         125  
227              
228              
229             =head1 POSSIBLE ERRORS
230              
231             Each possible error in HTML::Lint has a code. These codes are used
232             to identify each error for when you need to turn off error checking
233             for a specific error.
234              
235             =cut
236              
237             %errors = ( ## no critic ( ValuesAndExpressions::RequireInterpolationOfMetachars )
238             'api-parse-not-called' => ['The parse() method has not been called on this file.', CONFIG],
239             'api-eof-not-called' => ['The eof() method has not been called on this file.', CONFIG],
240             'config-unknown-directive' => ['Unknown directive "${directive}"', CONFIG],
241             'config-unknown-value' => ['Unknown value "${value}" for ${directive} directive', CONFIG],
242              
243             'elem-empty-but-closed' => ['<${tag}> is not a container -- is not allowed', STRUCTURE],
244             'elem-img-alt-missing' => [' does not have ALT text defined', HELPER],
245             'elem-img-sizes-missing' => [' tag has no HEIGHT and WIDTH attributes', HELPER],
246             'elem-input-alt-missing' => [' does not have non-blank ALT text defined', HELPER],
247             'elem-nonrepeatable' => ['<${tag}> is not repeatable, but already appeared at ${where}', STRUCTURE],
248             'elem-unclosed' => ['<${tag}> at ${where} is never closed', STRUCTURE],
249             'elem-unknown' => ['Unknown element <${tag}>', STRUCTURE],
250             'elem-unopened' => [' with no opening <${tag}>', STRUCTURE],
251              
252             'doc-tag-required' => ['<${tag}> tag is required', STRUCTURE],
253              
254             'attr-repeated' => ['${attr} attribute in <${tag}> is repeated', STRUCTURE],
255             'attr-unknown' => ['Unknown attribute "${attr}" for tag <${tag}>', FLUFF],
256             'attr-unclosed-entity' => ['Entity ${entity} is missing its closing semicolon', STRUCTURE],
257             'attr-unknown-entity' => ['Entity ${entity} is unknown', STRUCTURE],
258             'attr-use-entity' => ['Character "${char}" should be written as ${entity}', STRUCTURE],
259              
260             'text-unclosed-entity' => ['Entity ${entity} is missing its closing semicolon', STRUCTURE],
261             'text-unknown-entity' => ['Entity ${entity} is unknown', STRUCTURE],
262             'text-use-entity' => ['Character "${char}" should be written as ${entity}', STRUCTURE],
263             );
264              
265             =head2 api-parse-not-called
266              
267             You called the C method before calling C and C.
268              
269             =head2 api-eof-not-called
270              
271             You called the C method before calling C.
272              
273             =head2 config-unknown-directive
274              
275             Unknown directive "DIRECTIVE"
276              
277             You specified a directive in a comment for HTML::Lint that it didn't recognize.
278              
279             =head2 config-unknown-value
280              
281             Unknown value "VALUE" for DIRECTIVE directive
282              
283             Directive values can only be "on", "off", "yes", "no", "true", "false", "0" and "1".
284              
285             =head2 elem-unknown
286              
287             HTML::Lint doesn't know recognize the tag.
288              
289             =head2 elem-unopened
290              
291             C<< >> with no opening C<< >>.
292              
293             =head2 elem-unclosed
294              
295             C<< >> at WHERE is never closed.
296              
297             =head2 elem-empty-but-closed
298              
299             C<< >> is not a container -- C<< >> is not allowed.
300              
301             =head2 elem-img-alt-missing
302              
303             C<< >> does not have ALT text defined.
304              
305             =head2 elem-img-sizes-missing
306              
307             C<< >> tag has no HEIGHT and WIDTH attributes.
308              
309             =head2 elem-nonrepeatable
310              
311             C<< >> is not repeatable, but already appeared at WHERE.
312              
313             =head2 doc-tag-required
314              
315             C<< >> tag is required.
316              
317             =head2 attr-repeated
318              
319             ATTR attribute in C<< >> is repeated.
320              
321             =head2 attr-unknown
322              
323             Unknown attribute "ATTR" for tag C<< >>.
324              
325             =head2 text-unclosed-entity
326              
327             Entity ENTITY is missing its closing semicolon
328              
329             =head2 text-unknown-entity
330              
331             Entity ENTITY is unknown
332              
333             =head2 text-use-entity
334              
335             Character "CHAR" should be written as ENTITY
336              
337             =head1 COPYRIGHT & LICENSE
338              
339             Copyright 2005-2018 Andy Lester.
340              
341             This program is free software; you can redistribute it and/or modify it
342             under the terms of the Artistic License v2.0.
343              
344             http://www.opensource.org/licenses/Artistic-2.0
345              
346             Please note that these modules are not products of or supported by the
347             employers of the various contributors to the code.
348              
349             =head1 AUTHOR
350              
351             Andy Lester, C
352              
353             =cut
354              
355             1; # happy
356              
357             __DATA__