File Coverage

blib/lib/Tags/Output/Indent.pm
Criterion Covered Total %
statement 252 258 97.6
branch 62 80 77.5
condition 23 41 56.1
subroutine 28 29 96.5
pod 2 2 100.0
total 367 410 89.5


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