File Coverage

lib/Mail/AuthenticationResults/FoldableHeader.pm
Criterion Covered Total %
statement 132 138 95.6
branch 26 30 86.6
condition 7 9 77.7
subroutine 23 25 92.0
pod 17 17 100.0
total 205 219 93.6


line stmt bran cond sub pod time code
1             package Mail::AuthenticationResults::FoldableHeader;
2             # ABSTRACT: Class for modelling a foldable header string
3              
4             require 5.008;
5 28     28   193 use strict;
  28         91  
  28         834  
6 28     28   151 use warnings;
  28         52  
  28         1075  
7             our $VERSION = '2.20210914'; # VERSION
8 28     28   145 use Carp;
  28         49  
  28         1470  
9              
10 28     28   11097 use Mail::AuthenticationResults::Token::String;
  28         70  
  28         948  
11 28     28   10688 use Mail::AuthenticationResults::Token::Space;
  28         65  
  28         767  
12 28     28   10673 use Mail::AuthenticationResults::Token::Separator;
  28         66  
  28         770  
13 28     28   10768 use Mail::AuthenticationResults::Token::Comment;
  28         80  
  28         823  
14 28     28   10745 use Mail::AuthenticationResults::Token::Assignment;
  28         67  
  28         38064  
15              
16              
17             sub new {
18 101     101 1 242 my ( $class, $args ) = @_;
19              
20 101         189 my $self = {};
21 101         213 bless $self, $class;
22              
23 101         311 $self->{ 'string' } = [];
24              
25 101         228 return $self;
26             }
27              
28              
29             sub eol {
30 101     101 1 169 my ( $self ) = @_;
31 101 100       251 return $self->{ 'eol' } if exists ( $self->{ 'eol' } );
32 72         130 return "\n";
33             }
34              
35              
36             sub set_eol {
37 29     29 1 66 my ( $self, $eol ) = @_;
38 29         90 $self->{ 'eol' } = $eol;
39 29         55 return $self;
40             }
41              
42              
43             sub indent {
44 101     101 1 188 my ( $self ) = @_;
45 101 100       277 return $self->{ 'indent' } if exists ( $self->{ 'indent' } );
46 72         121 return ' ';
47             }
48              
49              
50             sub set_indent {
51 29     29 1 81 my ( $self, $indent ) = @_;
52 29         67 $self->{ 'indent' } = $indent;
53 29         54 return $self;
54             }
55              
56              
57             sub sub_indent {
58 101     101 1 173 my ( $self ) = @_;
59 101 100       218 return $self->{ 'sub_indent' } if exists ( $self->{ 'sub_indent' } );
60 72         115 return ' ';
61             }
62              
63              
64             sub set_sub_indent {
65 29     29 1 73 my ( $self, $indent ) = @_;
66 29         61 $self->{ 'sub_indent' } = $indent;
67 29         51 return $self;
68             }
69              
70              
71             sub try_fold_at {
72 418     418 1 605 my ( $self ) = @_;
73 418 100       838 return $self->{ 'try_fold_at' } if exists ( $self->{ 'try_fold_at' } );
74 331         690 return 800;
75             }
76              
77              
78             sub set_try_fold_at {
79 3     3 1 7 my ( $self, $length ) = @_;
80 3         7 $self->{ 'try_fold_at' } = $length;
81 3         5 return $self;
82             }
83              
84              
85             sub force_fold_at {
86 0     0 1 0 my ( $self ) = @_;
87 0 0       0 return $self->{ 'force_fold_at' } if exists ( $self->{ 'force_fold_at' } );
88 0         0 return 900;
89             }
90              
91              
92             sub set_force_fold_at {
93 0     0 1 0 my ( $self, $length ) = @_;
94 0         0 $self->{ 'force_fold_at' } = $length;
95 0         0 return $self;
96             }
97              
98              
99             sub string {
100 485     485 1 783 my( $self, $string ) = @_;
101 485         589 push @{ $self->{ 'string' } }, Mail::AuthenticationResults::Token::String->new_from_value( $string );
  485         1172  
102 485         802 return $self;
103             }
104              
105              
106             sub space {
107 341     341 1 597 my ( $self, $string ) = @_;
108 341         398 push @{ $self->{ 'string' } }, Mail::AuthenticationResults::Token::Space->new_from_value( $string );
  341         856  
109 341         558 return $self;
110             }
111              
112              
113             sub separator {
114 91     91 1 180 my ( $self, $string ) = @_;
115 91         134 push @{ $self->{ 'string' } }, Mail::AuthenticationResults::Token::Separator->new_from_value( $string );
  91         303  
116 91         153 return $self;
117             }
118              
119              
120             sub comment {
121 73     73 1 141 my ( $self, $string ) = @_;
122 73         100 push @{ $self->{ 'string' } }, Mail::AuthenticationResults::Token::Comment->new_from_value( $string );
  73         296  
123 73         140 return $self;
124             }
125              
126              
127             sub assignment {
128 209     209 1 348 my ( $self, $string ) = @_;
129 209         267 push @{ $self->{ 'string' } }, Mail::AuthenticationResults::Token::Assignment->new_from_value( $string );
  209         580  
130 209         346 return $self;
131             }
132              
133              
134             sub as_string {
135 101     101 1 186 my ( $self ) = @_;
136              
137 101         166 my $string = q{};
138 101         145 my $string_length = 0;
139 101         148 my $content_added = 0;
140              
141 101         174 my $sections = [];
142 101         150 my $stack = [];
143 101         156 my $last_type;
144              
145 101         145 foreach my $part ( @{ $self->{ 'string' } } ) {
  101         217  
146 1199 100 100     2196 if ( $part->is() eq 'space' && $last_type ne 'space' ) {
147             # We have a folding space
148 260 50       550 push @$sections, $stack if @$stack;
149 260         395 $stack = [];
150             }
151 1199         1688 push @$stack, $part;
152 1199         1996 $last_type = $part->is();
153             }
154 101 100       306 push @$sections, $stack if @$stack;
155              
156 101         255 my $eol = $self->eol();;
157 101         226 my $indent = $self->indent();
158 101         250 my $sub_indent = $self->sub_indent();
159              
160 101         166 my $fold_length = 0;
161             SECTION:
162 101         328 while ( my $section = shift @$sections ) {
163 382 100 100     789 if ( $section->[0]->is() eq 'space' && $section->[0]->value() eq $eol ) {
164             # This section starts a new line
165 111         152 $fold_length = 0;
166 111 100       269 if ( ! exists( $section->[0]->{ '_folded' } ) ) {
167 84 100       169 if ( $section->[1]->is() eq 'space' ) {
168             # Take the last indent value for the fold indent
169 81         138 $indent = $section->[1]->value();
170             }
171             }
172             }
173              
174 382         704 my $section_string = join( q{}, map { $_->value() } @$section );
  1316         2116  
175 382         643 my $section_length = length( $section_string );
176              
177 382 100       703 if ( $fold_length + $section_length > $self->try_fold_at() ) {
178 21 100       36 if ( $fold_length > 0 ) {
179             # Remove whitespace tokens at beginning of section
180 15         32 while ( $section->[0]->is() eq 'space' ) {
181 15         32 shift @$section;
182             }
183             # Insert new folding whitespace at beginning of section
184 15         41 unshift @$section, Mail::AuthenticationResults::Token::Space->new_from_value( $indent . $sub_indent );
185 15         33 unshift @$section, Mail::AuthenticationResults::Token::Space->new_from_value( $eol );
186 15         23 $section->[0]->{ '_folded' } = 1;
187 15         67 unshift @$sections, $section;
188 15         54 next SECTION;
189             }
190             else {
191             # ToDo:
192             # This section alone is over the line limit
193             # It already starts with a fold, so we need to remove
194             # some of it to a new line if we can.
195              
196             # Strategy 1: Fold at a relevant token boundary
197 6         9 my $first_section = [];
198 6         11 my $second_section = [];
199 6         14 push @$second_section, Mail::AuthenticationResults::Token::Space->new_from_value( $eol );
200 6         14 push @$second_section, Mail::AuthenticationResults::Token::Space->new_from_value( $indent . $sub_indent );
201 6         11 $second_section->[0]->{ '_folded' } = 1;
202 6         8 my $first_section_length = 0;
203 6         10 foreach my $part ( @$section ) {
204 30         45 my $part_length = length $part->value();
205 30 100       46 if ( $part_length + $first_section_length < $self->try_fold_at() ) {
206 24         31 push @$first_section, $part;
207 24         38 $first_section_length += $part_length;
208             }
209             else {
210 6         8 push @$second_section, $part;
211 6         10 $first_section_length = $self->try_fold_at() + 1; # everything from this point goes onto second
212             }
213             }
214             # Do we have a first and second section with actual content?
215 6 50 33     19 if ( ( grep { $_->is() ne 'space' } @$first_section ) &&
  24         47  
216 18         32 ( grep { $_->is() ne 'space' } @$second_section ) ) {
217 6         11 unshift @$sections, $second_section;
218 6         9 unshift @$sections, $first_section;
219 6         17 next SECTION;
220             }
221              
222             # We MUST fold at $self->force_fold_at();
223             # Strategy 2: Force fold at a space within a string
224             # Strategy 3: Force fold anywhere
225              
226             # We assume that force fold is greater than try fold
227             }
228             }
229              
230 361         623 $string .= $section_string;
231 361         890 $fold_length += $section_length;
232             }
233              
234 101         1195 return $string;
235             }
236              
237             1;
238              
239             __END__