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   170036 use warnings;
  42         97  
  42         1131  
4 42     42   178 use strict;
  42         62  
  42         787  
5              
6 42     42   5479 use parent 'Exporter';
  42         3589  
  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   5983 use constant CONFIG => 1;
  42         89  
  42         3626  
58 42     42   230 use constant STRUCTURE => 2;
  42         85  
  42         1785  
59 42     42   218 use constant HELPER => 3;
  42         94  
  42         1826  
60 42     42   224 use constant FLUFF => 4;
  42         84  
  42         29788  
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 300 my $class = shift;
70              
71 99         155 my $file = shift;
72 99         134 my $line = shift;
73 99         152 my $column = shift;
74 99         177 my $errcode = shift;
75 99         216 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         423 my $self = {
80             _file => $file,
81             _line => $line,
82             _column => $column,
83             _errcode => $errcode,
84             _errtext => undef,
85             _type => undef,
86             };
87              
88 99         202 bless $self, $class;
89              
90 99         291 $self->_expand_error( $errcode, @errparms );
91              
92 99         254 return $self;
93             }
94              
95             sub _expand_error {
96 99     99   147 my $self = shift;
97              
98 99         133 my $errcode = shift;
99              
100 99         219 my $specs = $errors{$errcode};
101 99         119 my $str;
102 99 50       224 if ( $specs ) {
103 99         159 ($str, $self->{_type}) = @{$specs};
  99         362  
104             }
105             else {
106 0         0 $str = "Unknown code: $errcode";
107             }
108              
109 99 50       245 if ( defined $str ) {
110 99         241 while ( @_ ) {
111 120         177 my $var = shift;
112 120         186 my $val = shift;
113 120         1366 $str =~ s/\$\{$var\}/$val/g;
114             }
115             }
116              
117 99         216 $self->{_errtext} = $str;
118              
119 99         181 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 35 my $self = shift;
133              
134 18         34 for my $matcher ( @_ ) {
135 25 100       47 return $matcher if $matcher eq $self->type;
136             }
137              
138 12         41 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 153 my $line;
168             my $col;
169              
170 85 100       209 if ( not ref $_[0] ) {
171 15         24 $line = shift;
172 15         25 $col = shift;
173             }
174             else {
175 70         100 my $self = shift;
176 70         128 $line = $self->line;
177 70         153 $col = $self->column;
178             }
179 85   100     229 $col ||= 0;
180 85         486 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 1859 my $self = shift;
191              
192 70         170 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 97 sub file { my $self = shift; return $self->{_file} || '' }
  70         272  
222 70   50 70 1 123 sub line { my $self = shift; return $self->{_line} || '' }
  70         174  
223 70   100 70 1 97 sub column { my $self = shift; return $self->{_column} || '' }
  70         199  
224 70   50 70 1 52500 sub errcode { my $self = shift; return $self->{_errcode} || '' }
  70         336  
225 70   50 70 1 110 sub errtext { my $self = shift; return $self->{_errtext} || '' }
  70         376  
226 25   50 25 1 33 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__