File Coverage

blib/lib/Text/Amuse/Element.pm
Criterion Covered Total %
statement 132 150 88.0
branch 56 68 82.3
condition 43 62 69.3
subroutine 35 40 87.5
pod 35 35 100.0
total 301 355 84.7


line stmt bran cond sub pod time code
1             package Text::Amuse::Element;
2 46     46   52405 use strict;
  46         72  
  46         1005  
3 46     46   156 use warnings;
  46         64  
  46         757  
4 46     46   9902 use utf8;
  46         277  
  46         205  
5              
6             =head1 NAME
7              
8             Text::Amuse::Element - Helper for Text::Amuse
9              
10             =head1 METHODS/ACCESSORS
11              
12             Everything here is pretty much internal only, underdocumented and
13             subject to change.
14              
15             =over 4
16              
17             =item new(%args)
18              
19             Constructor
20              
21             =cut
22              
23             sub new {
24 27817     27817 1 59606 my ($class, %args) = @_;
25 27817         167402 my $self = {
26             rawline => '',
27             raw_without_anchors => '',
28             block => '', # the block it says to belong
29             type => 'null', # the type
30             string => '', # the string
31             removed => '', # the portion of the string removed
32             attribute => '', # optional attribute for desclists
33             indentation => 0,
34             attribute_type => '',
35             style => 'X',
36             start_list_index => 0,
37             element_number => 0,
38             footnote_number => 0,
39             footnote_symbol => '',
40             footnote_index => '',
41             anchors => [],
42             language => '',
43             };
44 27817         33549 my %provided;
45 27817         96878 foreach my $accessor (keys %$self) {
46 472889 100 66     677317 if (exists $args{$accessor} and defined $args{$accessor}) {
47 111285         122995 $self->{$accessor} = $args{$accessor};
48 111285         127045 $provided{$accessor} = 1;
49             }
50             }
51 27817 100       49941 unless ($provided{indentation}) {
52 26117         34911 $self->{indentation} = length($self->{removed});
53             }
54              
55             die "anchors passed to the constructor but not a reference $self->{anchors}"
56 27817 50       45865 unless ref($self->{anchors}) eq 'ARRAY';
57              
58 27817 100 66     40983 if (exists $args{anchor} and length $args{anchor}) {
59 420         461 push @{$self->{anchors}}, $args{anchor};
  420         774  
60             }
61              
62 27817         68567 bless $self, $class;
63             }
64              
65             =item language
66              
67             Accessor to the language attribute
68              
69             =cut
70              
71             sub language {
72 4922     4922 1 11353 shift->{language};
73             }
74              
75             =item rawline
76              
77             Accessor to the raw input line
78              
79             =cut
80              
81             sub rawline {
82 9575     9575 1 23291 my $self = shift;
83 9575         17392 return $self->{rawline};
84             }
85              
86             =item raw_without_anchors
87              
88             Return the original string, but with anchors stripped out.
89              
90             =cut
91              
92             sub raw_without_anchors {
93 7216     7216 1 7254 my $self = shift;
94 7216         10919 return $self->{raw_without_anchors};
95             }
96              
97             sub _reset_rawline {
98 0     0   0 my ($self, $line) = @_;
99 0         0 $self->{rawline} = $line;
100             }
101              
102             =item will_not_merge
103              
104             Attribute to mark if an element cannot be further merged
105              
106             =cut
107              
108             sub will_not_merge {
109 23663     23663 1 27192 my ($self, $arg) = @_;
110 23663 50       28899 if (defined $arg) {
111 0         0 $self->{_will_not_merge} = $arg;
112             }
113 23663         34965 return $self->{_will_not_merge};
114             }
115              
116             =item anchors
117              
118             A list of anchors for this element.
119              
120             =item add_to_anchors(@list)
121              
122             Add the anchors passed to the constructor to this element.
123              
124             =item remove_anchors
125              
126             Empty the anchors array in the element
127              
128             =item move_anchors_to($element)
129              
130             Remove the anchors from this element and add them to the one passed as
131             argument.
132              
133             =cut
134              
135             sub anchors {
136 56720     56720 1 56663 my $self = shift;
137 56720         51924 return @{$self->{anchors}};
  56720         130468  
138             }
139              
140             sub add_to_anchors {
141 4926     4926 1 6372 my ($self, @anchors) = @_;
142 4926         4895 push @{$self->{anchors}}, @anchors;
  4926         10475  
143             }
144              
145             sub remove_anchors {
146 296     296 1 387 my ($self) = @_;
147 296         617 $self->{anchors} = [];
148             }
149              
150             sub move_anchors_to {
151 296     296 1 471 my ($self, $el) = @_;
152 296         423 $el->add_to_anchors($self->anchors);
153 296         484 $self->remove_anchors;
154             }
155              
156             =back
157              
158             =head2 ACCESSORS
159              
160             The following accessors set the value if an argument is provided.
161              
162             =over 4
163              
164             =item block
165              
166             The block the string belongs
167              
168             =cut
169              
170             sub block {
171 46629     46629 1 45186 my $self = shift;
172 46629 100       57338 if (@_) {
173 1829         2046 $self->{block} = shift;
174             }
175 46629   66     99965 return $self->{block} || $self->type;
176             }
177              
178             =item type
179              
180             The type
181              
182             =cut
183              
184             sub type {
185 565011     565011 1 544853 my $self = shift;
186 565011 100       666294 if (@_) {
187 1720         2125 $self->{type} = shift;
188             }
189 565011         1121829 return $self->{type};
190             }
191              
192             =item string
193              
194             The string (without the indentation or the leading markup)
195              
196             =cut
197              
198             sub string {
199 44547     44547 1 44988 my $self = shift;
200 44547 50       57930 if (@_) {
201 0         0 $self->{string} = shift;
202             }
203 44547         130543 return $self->{string};
204             }
205              
206             =item removed
207              
208             The portion of the string stripped out
209              
210             =cut
211              
212             sub removed {
213 62     62 1 107 my $self = shift;
214 62 50       124 if (@_) {
215 0         0 die "Read only attribute!";
216             }
217 62         463 return $self->{removed};
218             }
219              
220             =item style
221              
222             The block style. Default to C, read only. Used for aliases of tags,
223             when closing it requires a matching style.
224              
225             =cut
226              
227             sub style {
228 1030     1030 1 1140 my $self = shift;
229 1030 50       1491 die "Read only attribute!" if @_;
230 1030         1989 return $self->{style};
231             }
232              
233             =item indentation
234              
235             The indentation level, as a numerical value
236              
237             =cut
238              
239             sub indentation {
240 14559     14559 1 22934 return shift->{indentation};
241             }
242              
243             =item footnote_number
244              
245             The footnote number
246              
247             =cut
248              
249             sub footnote_number {
250 1308     1308 1 2516 return shift->{footnote_number};
251             }
252              
253             =item footnote_symbol
254              
255             The footnote symbol
256              
257             =cut
258              
259             sub footnote_symbol {
260 1929     1929 1 3717 return shift->{footnote_symbol};
261             }
262              
263             =item footnote_index
264              
265             The footnote index
266              
267             =cut
268              
269             sub footnote_index {
270 1354     1354 1 2697 return shift->{footnote_index};
271             }
272              
273              
274              
275              
276             =item attribute
277              
278             Accessor to attribute
279              
280             =cut
281              
282             sub attribute {
283 1557     1557 1 3683 return shift->{attribute};
284             }
285              
286             =item attribute_type
287              
288             Accessor to attribute_type
289              
290             =cut
291              
292             sub attribute_type {
293 393     393 1 791 return shift->{attribute_type};
294             }
295              
296              
297             =item start_list_index
298              
299             Accessor rw to start_list_index (defaults to 0)
300              
301             =cut
302              
303             sub start_list_index {
304 13067     13067 1 14360 my $self = shift;
305 13067 100       17347 if (@_) {
306 3365         3224 my $arg = shift;
307 3365 50       4313 if (defined $arg) {
308 3365         3567 $self->{start_list_index} = $arg;
309             }
310             }
311 13067         21146 return $self->{start_list_index};
312             }
313              
314             =back
315              
316             =head2 HELPERS
317              
318             =over 4
319              
320             =item is_start_block($blockname)
321              
322             Return true if the element is a "startblock" of the required block name
323              
324             =cut
325              
326             sub is_start_block {
327 51704     51704 1 53307 my $self = shift;
328 51704   50     62770 my $block = shift || "";
329 51704 100 100     56117 if ($self->type eq 'startblock' and $self->block eq $block) {
330 356         777 return 1;
331             } else {
332 51348         95612 return 0;
333             }
334             }
335              
336             =item is_stop_element($element)
337              
338             Return true if the element is a matching stopblock for the element
339             passed as argument.
340              
341             =cut
342              
343             sub is_stop_element {
344 2352     2352 1 3384 my ($self, $element) = @_;
345 2352 100 66     4303 if ($element and
      100        
      100        
346             $self->type eq 'stopblock' and
347             $self->block eq $element->type and
348             $self->style eq $element->style) {
349 322         781 return 1;
350             }
351             else {
352 2030         4181 return 0;
353             }
354             }
355              
356             =item is_regular_maybe
357              
358             Return true if the element is "regular", i.e., it just have trailing
359             white space
360              
361             =cut
362              
363             sub is_regular_maybe {
364 0     0 1 0 my $self = shift;
365 0 0 0     0 if ($self->type eq 'li' or
      0        
366             $self->type eq 'null' or
367             $self->type eq 'regular') {
368 0         0 return 1;
369             } else {
370 0         0 return 0;
371             }
372             }
373              
374             =item can_merge_next
375              
376             Return true if the element will merge the next one
377              
378             =cut
379              
380             sub can_merge_next {
381 15205     15205 1 15395 my $self = shift;
382 15205 50       18324 return 0 if $self->will_not_merge;
383 15205         47268 my %nomerge = (
384             bidimarker => 1,
385             stopblock => 1,
386             startblock => 1,
387             null => 1,
388             table => 1,
389             versep => 1,
390             newpage => 1,
391             inlinecomment => 1,
392             comment => 1,
393             );
394 15205 100       18647 if ($nomerge{$self->type}) {
395 6747         17018 return 0;
396             } else {
397 8458         23515 return 1;
398             }
399             }
400              
401             =item can_be_merged
402              
403             Return true if the element will merge the next one. Only regular strings.
404              
405             =cut
406              
407             sub can_be_merged {
408 8458     8458 1 9577 my $self = shift;
409 8458 50       10462 return 0 if $self->will_not_merge;
410 8458 100 66     10450 if ($self->type eq 'regular' or $self->type eq 'verse') {
411 2620         5541 return 1;
412             }
413             else {
414 5838         11942 return 0;
415             }
416             }
417              
418             =item can_be_in_list
419              
420             Return true if the element can be inside a list
421              
422             =cut
423              
424             sub can_be_in_list {
425 0     0 1 0 my $self = shift;
426 0 0 0     0 if ($self->type eq 'li' or
      0        
427             $self->type eq 'null', or
428             $self->type eq 'regular') {
429 0         0 return 1;
430             } else {
431 0         0 return 0;
432             }
433             }
434              
435             =item can_be_regular
436              
437             Return true if the element is quote, center, right
438              
439             =cut
440              
441             sub can_be_regular {
442 17391     17391 1 15937 my $self = shift;
443 17391 100       17848 return 0 unless $self->type eq 'regular';
444 4524 100 100     5421 if ($self->block eq 'quote' or
      100        
445             $self->block eq 'center' or
446             $self->block eq 'right') {
447 279         628 return 1;
448             }
449             else {
450 4245         6891 return 0;
451             }
452             }
453              
454              
455             =item should_close_blocks
456              
457             =cut
458              
459             sub should_close_blocks {
460 3158     3158 1 3275 my $self = shift;
461 3158 100       3933 return 0 if $self->type eq 'regular';
462 1262 100       1758 return 1 if $self->type =~ m/h[1-5]/;
463 1252 100       2739 return 1 if $self->block eq 'example';
464 1246 100       1566 return 1 if $self->block eq 'verse';
465 1240 100       1632 return 1 if $self->block eq 'table';
466 1234 100       1536 return 1 if $self->type eq 'newpage';
467 1231         2577 return 0;
468             }
469              
470              
471             =item add_to_string($string, $other_string, [...])
472              
473             Append (just concatenate) the given strings to the string attribute.
474              
475             =cut
476              
477             sub add_to_string {
478 0     0 1 0 my ($self, @args) = @_;
479 0         0 my $orig = $self->string;
480 0         0 $self->_reset_rawline(); # we modify the string, so throw away the rawline
481 0         0 $self->string(join("", $orig, @args));
482             }
483              
484             =item append($element)
485              
486             Append the element passed as argument to this one, setting the raw_line
487              
488             =cut
489              
490             sub append {
491 6375     6375 1 7682 my ($self, $element) = @_;
492 6375         8584 $self->{rawline} .= $element->rawline;
493 6375         9765 $self->{raw_without_anchors} .= $element->raw_without_anchors;
494 6375         8374 my $type = $self->type;
495             # greedy elements
496 6375 100 100     15259 if ($type eq 'example') {
    100          
497 1745         2321 $self->{string} .= $element->rawline;
498             # ignore the anchors, they can't be inside.
499 1745         2711 return;
500             }
501             elsif ($type eq 'verse' or $type eq 'footnote') {
502 485         737 $self->{string} .= $element->raw_without_anchors;
503             }
504             else {
505 4145         6598 $self->{string} .= $element->string;
506             }
507             # inherit the anchors
508 4630         6807 $self->add_to_anchors($element->anchors);
509             }
510              
511             =item can_append($element)
512              
513             =cut
514              
515             sub can_append {
516 15205     15205 1 19561 my ($self, $element) = @_;
517 15205 100 100     19686 if ($self->can_merge_next && $element->can_be_merged) {
518 2620         5879 return 1;
519             }
520 12585 100 100     15964 if ($self->type eq 'footnote' and
      100        
      66        
521             $element->type ne 'footnote' and
522             $element->type ne 'null' and
523             !$element->should_close_blocks) {
524 20         55 return 1;
525             }
526             # same type. Marked as can_merge_next => false
527 12565         18642 foreach my $type (qw/table versep null/) {
528 36743 100 100     39489 if ($self->type eq $type and $element->type eq $type) {
529 1518         3735 return 1;
530             }
531             }
532 11047         23409 return 0;
533             }
534              
535             =item become_regular
536              
537             Set block to empty string and type to regular
538              
539             =cut
540              
541             sub become_regular {
542 1611     1611 1 1648 my $self = shift;
543 1611         2516 $self->type('regular');
544 1611         2158 $self->block('');
545             }
546              
547             =item element_number
548              
549             Internal numbering of the element.
550              
551             =cut
552              
553             sub element_number {
554 0     0 1 0 return shift->{element_number};
555             }
556              
557             sub _set_element_number {
558 17820     17820   18941 my ($self, $num) = @_;
559 17820         24310 $self->{element_number} = $num;
560             }
561              
562             =item is_header
563              
564             Return 1 if the element type is h1/h6, 0 otherwise.
565              
566             =cut
567              
568             sub is_header {
569 2968     2968 1 3511 my $self = shift;
570 2968 100       4332 if ($self->type =~ m/h[1-6]/) {
571 1707         3841 return 1;
572             }
573             else {
574 1261         3325 return 0;
575             }
576             }
577              
578             =back
579              
580             =cut
581              
582             1;