File Coverage

blib/lib/String/Tools.pm
Criterion Covered Total %
statement 73 79 92.4
branch 41 62 66.1
condition 21 33 63.6
subroutine 13 13 100.0
pod 10 10 100.0
total 158 197 80.2


line stmt bran cond sub pod time code
1 1     1   607 use v5.12;
  1         4  
2              
3 1     1   7 use warnings;
  1         2  
  1         51  
4              
5             package String::Tools v0.19.045;
6             # ABSTRACT: Various tools for manipulating strings.
7              
8              
9 1     1   7 use Exporter 'import';
  1         1  
  1         1250  
10              
11             our @EXPORT = qw();
12             our @EXPORT_OK = qw(
13             define
14             is_blank
15             shrink
16             stitch
17             stitcher
18             stringify
19             subst
20             subst_vars
21             trim
22             trim_lines
23             );
24              
25             ### Variables ###
26              
27              
28             our $BLANK = '[[:cntrl:][:space:]]';
29              
30              
31             our $SUBST_VAR = qr/[[:alpha:]_]+\w*(?:[[:punct:]]\w+)*/;
32              
33              
34             our $THREAD = ' ';
35              
36             ### Functions ###
37              
38             sub stringify(_); # Forward declaration
39              
40              
41 6   66 6 1 41 sub define(_) { return $_[0] // !!undef }
42              
43              
44             sub is_blank(_) {
45 43     43 1 69 local $_ = &stringify;
46 43   100     314 return not( length() && !/\A$BLANK+\z/ );
47             }
48              
49              
50             sub shrink(_) {
51 3     3 1 7 local $_ = trim(&stringify);
52 3         36 s/$BLANK+/$THREAD/g;
53 3         17 return $_;
54             }
55              
56              
57             sub stitch {
58 7     7 1 12 my $str = '';
59 7         12 my $was_blank = 1;
60              
61 7         9 local $_;
62 7         18 foreach my $s (map stringify, @_) {
63 30         40 my $is_blank = is_blank($s);
64 30 100 100     88 $str .= $THREAD unless ( $was_blank || $is_blank );
65 30         41 $str .= $s;
66 30         53 $was_blank = $is_blank;
67             }
68              
69 7         36 return $str;
70             }
71              
72              
73             sub stitcher {
74 3   33 3 1 13 local $THREAD = shift // $THREAD;
75 3         6 return &stitch;
76             }
77              
78              
79             sub stringify(_) {
80 120     120 1 267 local ($_) = @_;
81              
82 120 100       207 return not( defined() ) ? define() : do {
83 118         162 my $ref = ref();
84 118 50 33     346 !$ref ? $_
    50          
    100          
    100          
    100          
85             : $ref eq 'ARRAY' ? "@$_"
86 2         16 : $ref eq 'HASH' ? "@{[%$_]}"
87             : $ref eq 'REF' && ref($$_) ne 'REF' ? stringify($$_)
88             : $ref eq 'SCALAR' ? stringify($$_)
89             : "$_"
90             ;
91             };
92             }
93              
94              
95             sub subst {
96 5     5 1 546 my $str = stringify( shift );
97 5 100 100     25 @_ = ( $_ ) if defined($_) && ! @_;
98 5 100       15 my %subst = 1 == @_ ? do {
99 3         5 my $ref = ref( $_[0] );
100             not($ref) ? ( _ => +shift )
101 1         4 : $ref eq 'ARRAY' ? @{ +shift }
102 3 50       11 : $ref eq 'HASH' ? %{ +shift }
  1 100       5  
    100          
103             : ( _ => +shift );
104             }
105             : @_;
106              
107 5 50       11 if (%subst) {
108 5         7 local $_;
109             my $names = '(?:'
110             . join( '|',
111             map quotemeta,
112 3 0       28 sort { length($b) <=> length($a) || $a cmp $b }
113 5 50       14 grep { length() && /\A$SUBST_VAR\z/ }
  8         164  
114             keys %subst
115             )
116             . ')\b';
117 5   66     97 $str =~ s[\$(?:\{\s*($names)\s*\}|($names))]
  8         42  
118             [ stringify( $subst{ $1 // $2 } ) ]eg;
119             }
120 5         42  
121             return $str;
122             }
123              
124              
125 2     2 1 6 sub subst_vars(_) {
126             local ($_) = &stringify;
127 2         130  
128 2         6 my @vars = /\$(\{\s*$SUBST_VAR\s*\}|$SUBST_VAR\b)/g;
129 9         43 my %seen = ();
130 2         4 return grep { !$seen{$_}++ }
  9         32  
131             map { trim( $_, qr/\{\s*/, qr/\s*\}/ ) } @vars;
132             }
133              
134              
135 19 50   19 1 52 sub trim {
136             local $_ = stringify( @_ ? shift : $_ );
137 19         29  
138 19         28 my ( $lead, $rear );
139 19 100       39 my $count = scalar @_;
    50          
140 0         0 if ($count == 0) {}
141             elsif ($count == 1) { $lead = shift; }
142             else {
143             # Could be:
144             # 1. l => $value
145             # 2. r => $value
146             # 3. l => $value, r => $value
147             # or r => $value, l => $value
148 15         36 # 4. $lead, $rear
149 15 100       37 my %lr = @_;
150 15 100       30 $lead = delete $lr{l} if exists $lr{l};
151             $rear = delete $lr{r} if exists $lr{r};
152             # At this point, there should be nothing in %lr,
153 15 100       38 # so if there is, then this must be case 4.
154             ( $lead, $rear ) = @_ if %lr;
155             }
156 19   66     50  
157 19 100       166 $lead //= $BLANK . '+';
158             s/\A$lead// if ( length $lead );
159 19   66     49  
160 19 100       136 $rear //= $lead;
161             s/$rear\z// if ( length $rear );
162 19         86  
163             return $_;
164             }
165              
166              
167 2 50   2 1 8 sub trim_lines {
168             local $_ = stringify( @_ ? shift : $_ );
169 2         5  
170 2         2 my ( $lead, $rear );
171 2 50       5 my $count = scalar @_;
    0          
172 0         0 if ($count == 0) {}
173             elsif ($count == 1) { $lead = shift; }
174             else {
175             # Could be:
176             # 1. l => $value
177             # 2. r => $value
178             # 3. l => $value, r => $value
179             # or r => $value, l => $value
180 0         0 # 4. $lead, $rear
181 0 0       0 my %lr = @_;
182 0 0       0 $lead = delete $lr{l} if exists $lr{l};
183             $rear = delete $lr{r} if exists $lr{r};
184             # At this point, there should be nothing in %lr,
185 0 0       0 # so if there is, then this must be case 4.
186             ( $lead, $rear ) = @_ if %lr;
187             }
188 2   33     13  
189 2 50       37 $lead //= $BLANK . '+';
190             s/^$lead//gm if ( length $lead );
191 2   33     19  
192 2 50       27 $rear //= $lead;
193             s/$rear$//gm if ( length $rear );
194 2         10  
195             return $_;
196             }
197              
198             1;
199              
200             __END__