File Coverage

blib/lib/Tags/Output/Indent.pm
Criterion Covered Total %
statement 256 262 97.7
branch 64 82 78.0
condition 23 41 56.1
subroutine 29 30 96.6
pod 2 2 100.0
total 374 417 89.6


line stmt bran cond sub pod time code
1             package Tags::Output::Indent;
2              
3 20     20   112612 use base qw(Tags::Output);
  20         124  
  20         8429  
4 20     20   682083 use strict;
  20         40  
  20         340  
5 20     20   80 use warnings;
  20         33  
  20         437  
6              
7 20     20   87 use Error::Pure qw(err);
  20         32  
  20         682  
8 20     20   7346 use Indent;
  20         11549  
  20         491  
9 20     20   7187 use Indent::Word;
  20         43851  
  20         566  
10 20     20   7117 use Indent::Block;
  20         15239  
  20         584  
11 20     20   112 use List::MoreUtils qw(none);
  20         37  
  20         153  
12 20     20   11952 use Readonly;
  20         39  
  20         762  
13 20     20   7188 use Tags::Utils qw(encode_attr_entities encode_char_entities);
  20         118549  
  20         353  
14 20     20   8626 use Tags::Utils::Preserve;
  20         22152  
  20         43279  
15              
16             # Constants.
17             Readonly::Scalar my $EMPTY_STR => q{};
18             Readonly::Scalar my $LAST_INDEX => -1;
19             Readonly::Scalar my $LINE_SIZE => 79;
20             Readonly::Scalar my $SPACE => q{ };
21              
22             our $VERSION = 0.08;
23              
24             # Finalize Tags output.
25             sub finalize {
26 4     4 1 1246 my $self = shift;
27              
28             # XML mode.
29 4 100       13 if ($self->{'xml'}) {
30              
31             # Add ending of all opened tags.
32 1         2 while (@{$self->{'printed_tags'}}) {
  2         8  
33 1         3 $self->put(['e', $self->{'printed_tags'}->[0]]);
34             }
35              
36             # SGML mode.
37             } else {
38              
39             # Flush tmp code.
40 3 50       6 if (scalar @{$self->{'tmp_code'}}) {
  3         10  
41 3         8 $self->_print_tag('>');
42             }
43 3         6 $self->{'printed_tags'} = [];
44             }
45 4         10 return;
46             }
47              
48             # Resets internal variables.
49             sub reset {
50 53     53 1 11287 my $self = shift;
51              
52             # Comment flag.
53 53         85 $self->{'comment_flag'} = 0;
54              
55             # Indent object.
56             $self->{'indent'} = Indent->new(
57 53         213 'next_indent' => $self->{'next_indent'},
58             );
59              
60             # Indent::Word object.
61             $self->{'indent_word'} = Indent::Word->new(
62 53         1537 'line_size' => $self->{'line_size'},
63             'next_indent' => $EMPTY_STR,
64             );
65              
66             # Indent::Block object.
67             $self->{'indent_block'} = Indent::Block->new(
68             'line_size' => $self->{'line_size'},
69 53         2339 'next_indent' => $self->{'next_indent'},
70             'strict' => 0,
71             );
72              
73             # Flush code.
74 53         2080 $self->_reset_flush;
75              
76             # Tmp code.
77 53         88 $self->{'tmp_code'} = [];
78 53         129 $self->{'tmp_comment_code'} = [];
79              
80             # Printed tags.
81 53         97 $self->{'printed_tags'} = [];
82              
83             # Non indent flag.
84 53         73 $self->{'non_indent'} = 0;
85              
86             # Flag, that means raw tag.
87 53         79 $self->{'raw_tag'} = 0;
88              
89             # Preserved object.
90             $self->{'preserve_obj'} = Tags::Utils::Preserve->new(
91 53         216 'preserved' => $self->{'preserved'},
92             );
93              
94             # Process flag.
95 53         1427 $self->{'process'} = 0;
96              
97 53         124 return;
98             }
99              
100             # Check parameters to rigth values.
101             sub _check_params {
102 32     32   497 my $self = shift;
103              
104             # Check params from SUPER.
105 32         129 $self->SUPER::_check_params();
106              
107             # Check 'attr_delimeter'.
108 30 100 66     268 if ($self->{'attr_delimeter'} ne q{"}
109             && $self->{'attr_delimeter'} ne q{'}) {
110              
111 1         5 err "Bad attribute delimeter '$self->{'attr_delimeter'}'.";
112             }
113              
114 29         53 return;
115             }
116              
117             # Default parameters.
118             sub _default_parameters {
119 34     34   17486 my $self = shift;
120              
121             # Default parameters from SUPER.
122 34         161 $self->SUPER::_default_parameters();
123              
124             # Attribute callback.
125 34         703 $self->{'attr_callback'} = \&encode_attr_entities;
126              
127             # Attribute delimeter.
128 34         68 $self->{'attr_delimeter'} = '"';
129              
130             # Indent CDATA section.
131 34         63 $self->{'cdata_indent'} = 0;
132              
133             # CDATA callback.
134 34         62 $self->{'cdata_callback'} = undef;
135              
136             # Data callback.
137 34         68 $self->{'data_callback'} = \&encode_char_entities;
138              
139             # Callback to instruction.
140 34         62 $self->{'instruction'} = $EMPTY_STR;
141              
142             # Indent line size.
143 34         61 $self->{'line_size'} = $LINE_SIZE;
144              
145             # Next indent string.
146 34         136 $self->{'next_indent'} = $SPACE x 2;
147              
148             # No data callback.
149 34         78 $self->{'no_data_callback'} = ['script', 'style'];
150              
151             # No simple tags.
152 34         62 $self->{'no_simple'} = [];
153              
154             # Preserved tags.
155 34         59 $self->{'preserved'} = [];
156              
157             # Raw data callback.
158 34         60 $self->{'raw_callback'} = undef;
159              
160             # XML output.
161 34         58 $self->{'xml'} = 0;
162              
163 34         68 return;
164             }
165              
166             # Helper for flush data.
167             sub _flush_code {
168 247     247   399 my ($self, $code) = @_;
169 247 100       431 if (! $self->{'process'}) {
170 52         84 $self->{'process'} = 1;
171             }
172 247         364 $self->{'flush_code'} .= $code;
173 247         328 return;
174             }
175              
176             # Print newline if need.
177             sub _newline {
178 149     149   214 my $self = shift;
179              
180             # Null raw tag (normal tag processing).
181 149 100       252 if ($self->{'raw_tag'}) {
182 9         11 $self->{'raw_tag'} = 0;
183              
184             # Adding newline if flush_code.
185             } else {
186 140         287 my (undef, $pre_pre) = $self->{'preserve_obj'}->get;
187 140 100 100     851 if ($self->{'process'} && $pre_pre == 0) {
188 87         162 $self->_flush_code($self->{'output_sep'});
189             }
190             }
191              
192 149         176 return;
193             }
194              
195             # Print indented tag from @{$self->{'tmp_code'}}.
196             sub _print_tag {
197 62     62   117 my ($self, $string) = @_;
198 62 50       164 if ($string) {
199 62 100       139 if ($string =~ /^\/>$/ms) {
200 9         30 push @{$self->{'tmp_code'}}, $SPACE;
  9         32  
201             }
202 62         95 push @{$self->{'tmp_code'}}, $string;
  62         126  
203             }
204              
205             # Flush comment code before tag.
206             # TODO Optimalization.
207 62 100 100     209 if ($self->{'comment_flag'} == 0
208 57         186 && scalar @{$self->{'tmp_comment_code'}}) {
209              
210             # Comment from tmp place.
211 4         4 foreach my $tmp_comment (@{$self->{'tmp_comment_code'}}) {
  4         7  
212 4         9 $self->_newline;
213             my $indent_tmp_comment = $self->{'indent_block'}
214 4         10 ->indent($tmp_comment, $self->{'indent'}->get);
215 4         384 $self->_flush_code($indent_tmp_comment);
216             }
217              
218 4         10 my $pre = $self->{'preserve_obj'}->get;
219 4         15 my $act_indent;
220 4 50 33     14 if (! $self->{'non_indent'} && ! $pre) {
221 4         8 $act_indent = $self->{'indent'}->get;
222             }
223 4         18 $self->_newline;
224              
225             # Get indent string and put to flush.
226             my $tmp = $self->{'indent_block'}->indent(
227 4 50       12 $self->{'tmp_code'}, $act_indent, $pre ? 1 : 0,
228             );
229 4         718 $self->_flush_code($tmp);
230              
231 4         7 $self->{'tmp_code'} = [];
232 4 50 33     12 if (! $self->{'non_indent'} && ! $pre) {
233 4         10 $self->{'indent'}->add;
234             }
235 4         31 $self->{'preserve_obj'}->begin($self->{'printed_tags'}->[0]);
236             } else {
237 58         158 my $pre = $self->{'preserve_obj'}->get;
238 58         248 my $act_indent;
239 58 50 33     220 if (! $self->{'non_indent'} && ! $pre) {
240 58         167 $act_indent = $self->{'indent'}->get;
241             }
242 58         301 $self->_newline;
243              
244             # Get indent string and put to flush.
245             my $tmp = $self->{'indent_block'}->indent(
246 58 50       209 $self->{'tmp_code'}, $act_indent, $pre ? 1 : 0
247             );
248 58         6321 $self->_flush_code($tmp);
249              
250 58         103 $self->{'tmp_code'} = [];
251 58 50 33     258 if (! $self->{'non_indent'} && ! $pre) {
252 58         153 $self->{'indent'}->add;
253             }
254 58         570 $self->{'preserve_obj'}->begin($self->{'printed_tags'}->[0]);
255              
256             # Comment from tmp place.
257 58         708 foreach my $tmp_comment (@{$self->{'tmp_comment_code'}}) {
  58         149  
258 4         9 $self->_newline;
259             my $indent_tmp_comment = $self->{'indent_block'}
260 4         12 ->indent($tmp_comment, $self->{'indent'}->get);
261 4         374 $self->_flush_code($indent_tmp_comment);
262             }
263             }
264 62         154 $self->{'tmp_comment_code'} = [];
265 62         105 return;
266             }
267              
268             # Print indented end of tag.
269             sub _print_end_tag {
270 47     47   76 my ($self, $string) = @_;
271 47         58 my $act_indent;
272 47         93 my ($pre, $pre_pre) = $self->{'preserve_obj'}->get;
273 47 50 33     324 if (! $self->{'non_indent'} && ! $pre) {
274 47         132 $self->{'indent'}->remove;
275 47 100       501 if (! $pre_pre) {
276 45         102 $act_indent = $self->{'indent'}->get;
277             }
278             }
279 47         221 $self->_newline;
280 47 50       183 my $indent_end = $self->{'indent_block'}->indent(
281             [''], $act_indent, $pre ? 1 : 0,
282             );
283 47         2757 $self->_flush_code($indent_end);
284 47         70 return;
285             }
286              
287             # Attributes.
288             sub _put_attribute {
289 20     20   325 my ($self, $attr, $value) = @_;
290              
291             # Check to 'tmp_code'.
292 20 50       27 if (! @{$self->{'tmp_code'}}) {
  20         47  
293 0         0 err 'Bad tag type \'a\'.';
294             }
295              
296             # Check to pairs in XML mode.
297 20 50 66     102 if ($self->{'xml'} && ! defined $value) {
298 0         0 err 'In XML mode must be a attribute value.';
299             }
300              
301             # Process data callback.
302 20         46 my @attr = ($attr);
303 20 50       49 if (defined $value) {
304 20         51 push @attr, $value;
305             }
306 20         71 $self->_process_callback(\@attr, 'attr_callback');
307              
308             # Process attribute.
309 20         2617 push @{$self->{'tmp_code'}}, $SPACE, $attr[0];
  20         50  
310 20 50       44 if (defined $attr[1]) {
311 20         72 push @{$self->{'tmp_code'}}, q{=}, $self->{'attr_delimeter'}.
312 20         24 $attr[1].$self->{'attr_delimeter'};
313             }
314              
315             # Reset comment flag.
316 20         56 $self->{'comment_flag'} = 0;
317              
318 20         52 return;
319             }
320              
321             # Begin of tag.
322             sub _put_begin_of_tag {
323 62     62   5027 my ($self, $tag) = @_;
324              
325             # Flush tmp code.
326 62 100       96 if (scalar @{$self->{'tmp_code'}}) {
  62         160  
327 10         29 $self->_print_tag('>');
328             }
329              
330             # TODO Add checking of XML element name.
331             # if ($self->{'xml'} && _check(element_name)) {
332             # err 'This is not XML format.';
333             # }
334              
335             # Push begin of tag to tmp code.
336 62         84 push @{$self->{'tmp_code'}}, "<$tag";
  62         161  
337              
338             # Added tag to printed tags.
339 62         92 unshift @{$self->{'printed_tags'}}, $tag;
  62         152  
340              
341 62         123 return;
342             }
343              
344             # CData.
345             sub _put_cdata {
346 6     6   66 my ($self, @cdata) = @_;
347              
348             # Flush tmp code.
349 6 100       11 if (scalar @{$self->{'tmp_code'}}) {
  6         19  
350 5         12 $self->_print_tag('>');
351             }
352              
353             # Added begin of cdata section.
354 6         15 unshift @cdata, '
355              
356             # Check to bad cdata.
357 6 100       26 if ((join $EMPTY_STR, @cdata) =~ /]]>$/ms) {
358 1         5 err 'Bad CDATA section.';
359             }
360              
361             # Added end of cdata section.
362 5         10 push @cdata, ']]>';
363              
364             # Process data callback.
365 5         24 $self->_process_callback(\@cdata, 'cdata_callback');
366              
367 5         41 $self->_newline;
368 5         14 $self->{'preserve_obj'}->save_previous;
369              
370             # TODO Proc tohle nejde volat primo?
371             my $tmp = $self->{'indent_block'}->indent(
372             \@cdata, $self->{'indent'}->get,
373 5 100       27 $self->{'cdata_indent'} == 1 ? 0 : 1,
374             );
375              
376             # To flush code.
377 5         486 $self->_flush_code($tmp);
378              
379 5         12 return;
380             }
381              
382             # Comment.
383             sub _put_comment {
384 12     12   157 my ($self, @comments) = @_;
385              
386             # Comment string.
387 12         23 unshift @comments, '';
390             } else {
391 11         16 push @comments, '-->';
392             }
393              
394             # Process comment.
395 12 100       26 if (scalar @{$self->{'tmp_code'}}) {
  12         24  
396 8         11 push @{$self->{'tmp_comment_code'}}, \@comments;
  8         13  
397              
398             # Flag, that means comment is last.
399 8         12 $self->{'comment_flag'} = 1;
400             } else {
401 4         10 $self->_newline;
402             my $indent_comment = $self->{'indent_block'}->indent(
403 4         12 \@comments, $self->{'indent'}->get,
404             );
405 4         435 $self->_flush_code($indent_comment);
406             }
407 12         26 return;
408             }
409              
410             # Data.
411             sub _put_data {
412 22     22   241 my ($self, @data) = @_;
413              
414             # Flush tmp code.
415 22 100       28 if (scalar @{$self->{'tmp_code'}}) {
  22         53  
416 20         49 $self->_print_tag('>');
417             }
418              
419             # Process data callback.
420 22 100   43   92 if (none { $_ eq $self->{'printed_tags'}->[0] } @{$self->{'no_data_callback'}}) {
  43         101  
  22         109  
421 21         88 $self->_process_callback(\@data, 'data_callback');
422             }
423              
424 22         2363 $self->_newline;
425 22         53 $self->{'preserve_obj'}->save_previous;
426 22         144 my $pre = $self->{'preserve_obj'}->get;
427             my $indent_data = $self->{'indent_word'}->indent(
428             (join $EMPTY_STR, @data),
429 22 100       157 $pre ? $EMPTY_STR : $self->{'indent'}->get,
    100          
430             $pre ? 1 : 0
431             );
432              
433 22         3237 $self->_flush_code($indent_data);
434 22         48 return;
435             }
436              
437             # End of tag.
438             sub _put_end_of_tag {
439 56     56   982 my ($self, $tag) = @_;
440 56         69 my $printed = shift @{$self->{'printed_tags'}};
  56         98  
441 56 50 66     177 if ($self->{'xml'} && $printed ne $tag) {
442 0         0 err "Ending bad tag: '$tag' in block of tag '$printed'.";
443             }
444              
445             # Tag can be simple.
446 56 100 33     157 if ($self->{'xml'} && (! scalar @{$self->{'no_simple'}}
      66        
447 0     0   0 || none { $_ eq $tag } @{$self->{'no_simple'}})) {
448              
449 23         67 my $pre = $self->{'preserve_obj'}->end($tag);
450 23 100       278 if (scalar @{$self->{'tmp_code'}}) {
  23         41  
451 12 100 100     16 if (scalar @{$self->{'tmp_comment_code'}}
  12         49  
452             && $self->{'comment_flag'} == 1) {
453              
454 3         9 $self->_print_tag('>');
455             # XXX $self->{'preserve_obj'}->end($tag);
456 3         18 $self->_print_end_tag($tag);
457             } else {
458 9         35 $self->_print_tag('/>');
459 9 50 33     34 if (! $self->{'non_indent'} && ! $pre) {
460 9         25 $self->{'indent'}->remove;
461             }
462             }
463             } else {
464 11         24 $self->_print_end_tag($tag);
465             }
466              
467             # Tag cannot be simple.
468             } else {
469 33 100       41 if (scalar @{$self->{'tmp_code'}}) {
  33         82  
470 6         16 unshift @{$self->{'printed_tags'}}, $tag;
  6         14  
471 6         19 $self->_print_tag('>');
472 6         6 shift @{$self->{'printed_tags'}};
  6         10  
473             # XXX $self->_newline;
474             }
475 33         94 $self->{'preserve_obj'}->end($tag);
476 33         405 $self->_print_end_tag($tag);
477             }
478 56         225 return;
479             }
480              
481             # Instruction.
482             sub _put_instruction {
483 1     1   42 my ($self, $target, $code) = @_;
484              
485             # Flush tmp code.
486 1 50       2 if (scalar @{$self->{'tmp_code'}}) {
  1         4  
487 0         0 $self->_print_tag('>');
488             }
489              
490             # Process instruction code.
491 1 50       4 if (ref $self->{'instruction'} eq 'CODE') {
492 0         0 $self->{'instruction'}->($self, $target, $code);
493              
494             # Print instruction.
495             } else {
496 1         4 $self->_newline;
497 1         3 $self->{'preserve_obj'}->save_previous;
498             my $indent_instr = $self->{'indent_block'}->indent(
499             ['',
500 1         9 $self->{'indent'}->get],
501             );
502 1         189 $self->_flush_code($indent_instr);
503             }
504              
505 1         3 return;
506             }
507              
508             # Raw data.
509             sub _put_raw {
510 11     11   155 my ($self, @raw_data) = @_;
511              
512             # Flush tmp code.
513 11 100       27 if (scalar @{$self->{'tmp_code'}}) {
  11         27  
514 6         11 $self->_print_tag('>');
515             }
516              
517             # Process data callback.
518 11         33 $self->_process_callback(\@raw_data, 'raw_callback');
519              
520             # Added raw data to flush code.
521 11         81 $self->_flush_code(join $EMPTY_STR, @raw_data);
522              
523             # Set raw flag.
524 11         16 $self->{'raw_tag'} = 1;
525              
526 11         19 return;
527             }
528              
529             # Reset flush code.
530             sub _reset_flush {
531 63     63   469 my $self = shift;
532 63         102 $self->{'flush_code'} = $EMPTY_STR;
533 63         85 return;
534             }
535              
536             1;
537              
538             __END__