File Coverage

blib/lib/Mail/DKIM/TextWrap.pm
Criterion Covered Total %
statement 72 73 98.6
branch 18 22 81.8
condition 14 14 100.0
subroutine 10 10 100.0
pod 5 6 83.3
total 119 125 95.2


line stmt bran cond sub pod time code
1             package Mail::DKIM::TextWrap;
2 2     2   138673 use strict;
  2         4  
  2         100  
3 2     2   12 use warnings;
  2         5  
  2         166  
4             our $VERSION = '1.20240923'; # VERSION
5             # ABSTRACT: text wrapping module written for use with DKIM
6              
7 2     2   16 use Carp;
  2         4  
  2         2483  
8              
9              
10             sub new {
11 9     9 1 246461 my $class = shift;
12 9         40 my %args = @_;
13 9         138 my $self = {
14             Margin => 72,
15             Break => qr/\s/,
16             BreakBefore => undef,
17             Swallow => qr/\s/,
18             Separator => "\n",
19             cur => 0,
20             may_break => 0,
21             soft_space => "",
22             word => "",
23             %args,
24             };
25 9   100     44 $self->{Output} ||= \*STDOUT;
26 9         56 return bless $self, $class;
27             }
28              
29             # Internal properties:
30             #
31             # cur - the last known column position
32             #
33             # may_break - nonzero if the current location allows a linebreak
34             #
35             # soft_space - contains added text that will not be printed if a linebreak
36             # occurs
37             #
38             # word - contains the current word
39              
40             # Internal methods:
41             #
42             # _calculate_new_column() - determine where cur would be after adding some text
43             #
44             # my $new_cur = _calculate_new_column($cur, "some additional\ntext");
45             #
46             sub _calculate_new_column {
47 446     446   885 my ( $cur, $text ) = @_;
48 446 50       799 confess "invalid argument" unless defined($text);
49              
50 446         1460 while ( $text =~ /^(.*?)([\n\r\t])(.*)$/s ) {
51 76         142 $cur += length($1);
52 76 100       205 if ( $2 eq "\t" ) {
53 18         43 $cur = ( int( $cur / 8 ) + 1 ) * 8;
54             }
55             else {
56 58         89 $cur = 0;
57             }
58 76         288 $text = $3;
59             }
60 446         693 $cur += length($text);
61 446         763 return $cur;
62             }
63              
64              
65             sub add {
66 122     122 1 2625 my ( $self, $text ) = @_;
67 122         228 my $break_after = $self->{Break};
68 122         206 my $break_before = $self->{BreakBefore};
69 122         182 my $swallow = $self->{Swallow};
70 122         227 $self->{word} .= $text;
71 122         302 while ( length $self->{word} ) {
72 471         642 my $word;
73 471 100 100     3972 if ( defined($break_before)
    100 100        
    100          
74             and $self->{word} =~ s/^(.+?)($break_before)/$2/s )
75             {
76             # note- $1 should have at least one character
77 16         37 $word = $1;
78             }
79             elsif ( defined($break_after)
80             and $self->{word} =~ s/^(.*?)($break_after)//s )
81             {
82 361         929 $word = $1 . $2;
83             }
84             elsif ( $self->{NoBuffering} ) {
85 22         45 $word = $self->{word};
86 22         36 $self->{word} = "";
87             }
88             else {
89 72         220 last;
90             }
91              
92 399 50       886 die "assertion failed" unless length($word) >= 1;
93              
94 399         593 my $next_soft_space;
95 399 100 100     1946 if ( defined($swallow) && $word =~ s/($swallow)$//s ) {
96 84         151 $next_soft_space = $1;
97             }
98             else {
99 315         550 $next_soft_space = "";
100             }
101              
102 399         695 my $to_print = $self->{soft_space} . $word;
103 399         758 my $new_pos = _calculate_new_column( $self->{cur}, $to_print );
104              
105 399 100 100     1074 if ( $new_pos > $self->{Margin} && $self->{may_break} ) {
106              
107             # what would happen if we put the separator in?
108             my $w_sep =
109 47         95 _calculate_new_column( $self->{cur}, $self->{Separator} );
110 47 100       118 if ( $w_sep < $self->{cur} ) {
111              
112             # inserting the separator gives us more room,
113             # so do it
114 46         138 $self->output( $self->{Separator} );
115 46         76 $self->{soft_space} = "";
116 46         88 $self->{cur} = $w_sep;
117 46         105 $self->{word} = $word . $next_soft_space . $self->{word};
118 46         127 next;
119             }
120             }
121              
122 353         823 $self->output($to_print);
123 353         609 $self->{soft_space} = $next_soft_space;
124 353         571 $self->{cur} = $new_pos;
125 353         897 $self->{may_break} = 1;
126             }
127             }
128              
129              
130             sub finish {
131 12     12 1 46 my $self = shift;
132 12         31 $self->flush;
133 12         43 $self->reset;
134             }
135              
136              
137             sub flush {
138 30     30 1 62 my $self = shift;
139              
140 30         94 local $self->{NoBuffering} = 1;
141 30         81 local $self->{Swallow} = undef;
142 30         63 $self->add("");
143             }
144              
145             sub output {
146 399     399 1 596 my $self = shift;
147 399         650 my $to_print = shift;
148              
149 399         670 my $out = $self->{Output};
150 399 50       1310 if ( UNIVERSAL::isa( $out, "GLOB" ) ) {
    50          
151 0         0 print $out $to_print;
152             }
153             elsif ( UNIVERSAL::isa( $out, "SCALAR" ) ) {
154 399         794 $$out .= $to_print;
155             }
156             }
157              
158             sub reset {
159 12     12 0 17 my $self = shift;
160 12         38 $self->{cur} = 0;
161 12         19 $self->{soft_space} = "";
162 12         30 $self->{word} = "";
163             }
164              
165             1;
166              
167             __END__