File Coverage

blib/lib/Tags/Output/Indent.pm
Criterion Covered Total %
statement 256 262 97.7
branch 66 84 78.5
condition 23 41 56.1
subroutine 29 30 96.6
pod 2 2 100.0
total 376 419 89.7


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