line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
15
|
|
|
15
|
|
1136743
|
use strict; |
|
15
|
|
|
|
|
42
|
|
|
15
|
|
|
|
|
704
|
|
2
|
15
|
|
|
15
|
|
88
|
use warnings; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
875
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package String::Sections; |
5
|
|
|
|
|
|
|
BEGIN { |
6
|
15
|
|
|
15
|
|
505
|
$String::Sections::AUTHORITY = 'cpan:KENTNL'; |
7
|
|
|
|
|
|
|
} |
8
|
|
|
|
|
|
|
{ |
9
|
|
|
|
|
|
|
$String::Sections::VERSION = '0.3.2'; |
10
|
|
|
|
|
|
|
} |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# ABSTRACT: Extract labeled groups of sub-strings from a string. |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
15
|
|
|
15
|
|
396
|
use 5.010001; |
|
15
|
|
|
|
|
59
|
|
|
15
|
|
|
|
|
696
|
|
17
|
15
|
|
|
15
|
|
18429
|
use Moo; |
|
15
|
|
|
|
|
293747
|
|
|
15
|
|
|
|
|
106
|
|
18
|
15
|
|
|
15
|
|
59832
|
use Types::Standard qw( RegexpRef Str Bool Maybe FileHandle ArrayRef ); |
|
15
|
|
|
|
|
1467151
|
|
|
15
|
|
|
|
|
252
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
our $TYPE_REGEXP = RegexpRef; |
21
|
|
|
|
|
|
|
our $TYPE_OPTIONAL_STRING = Maybe [Str]; |
22
|
|
|
|
|
|
|
our $TYPE_BOOL = Bool; |
23
|
|
|
|
|
|
|
our $TYPE_FILEHANDLE = FileHandle; |
24
|
|
|
|
|
|
|
our $TYPE_INPUT_LIST = ArrayRef [Str]; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
|
31
|
0
|
|
|
0
|
|
0
|
sub _croak { require Carp; goto &Carp::croak; } |
|
0
|
|
|
|
|
0
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub __add_line { |
35
|
|
|
|
|
|
|
|
36
|
50
|
|
|
50
|
|
93
|
my ( $self, $stash, $line ) = @_; |
37
|
|
|
|
|
|
|
|
38
|
50
|
100
|
|
|
|
67
|
if ( ${$line} =~ $self->header_regex ) { |
|
50
|
|
|
|
|
856
|
|
39
|
15
|
|
|
|
|
548
|
$stash->set_current("$1"); |
40
|
15
|
|
|
|
|
6280
|
$stash->append_data_to_current_section(); |
41
|
15
|
|
|
|
|
55
|
return 1; # 1 is next. |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# not valid for lists because lists are not likely to have __END__ in them. |
45
|
35
|
50
|
|
|
|
890
|
if ( $self->stop_at_end ) { |
46
|
0
|
0
|
|
|
|
0
|
return 0 if ${$line} =~ $self->document_end_regex; |
|
0
|
|
|
|
|
0
|
|
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
35
|
50
|
|
|
|
933
|
if ( $self->ignore_empty_prelude ) { |
50
|
35
|
50
|
33
|
|
|
544
|
return 1 if not $stash->has_current and ${$line} =~ $self->empty_line_regex; |
|
0
|
|
|
|
|
0
|
|
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
35
|
50
|
|
|
|
130
|
if ( not $stash->has_current ) { |
54
|
0
|
|
|
|
|
0
|
_croak( 'bogus data section: text outside named section. line: ' . ${$line} ); |
|
0
|
|
|
|
|
0
|
|
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
35
|
50
|
|
|
|
531
|
if ( $self->enable_escapes ) { |
58
|
0
|
|
|
|
|
0
|
my $regex = $self->line_escape_regex; |
59
|
0
|
|
|
|
|
0
|
${$line} =~ s{$regex}{}msx; |
|
0
|
|
|
|
|
0
|
|
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
35
|
|
|
|
|
481
|
$stash->append_data_to_current_section($line); |
63
|
|
|
|
|
|
|
|
64
|
35
|
|
|
|
|
73
|
return 1; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub load_list { |
69
|
8
|
|
|
8
|
1
|
57356
|
my ( $self, @rest ) = @_; |
70
|
8
|
|
|
|
|
66
|
$TYPE_INPUT_LIST->assert_valid( \@rest ); |
71
|
8
|
|
|
|
|
6506
|
require String::Sections::Result; |
72
|
8
|
|
|
|
|
65
|
my $result_ob = String::Sections::Result->new(); |
73
|
|
|
|
|
|
|
|
74
|
8
|
100
|
|
|
|
18977
|
if ( $self->default_name ) { |
75
|
2
|
|
|
|
|
2358
|
$result_ob->set_current( $self->default_name ); |
76
|
2
|
|
|
|
|
1512
|
$result_ob->append_data_to_current_section(); |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
8
|
|
|
|
|
164
|
for my $line (@rest) { |
80
|
26
|
|
|
|
|
97
|
my $result = $self->__add_line( $result_ob, \$line ); |
81
|
26
|
50
|
|
|
|
96
|
next if $result; |
82
|
0
|
0
|
|
|
|
0
|
last if not $result; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
} |
85
|
8
|
|
|
|
|
62
|
return $result_ob; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub load_string { |
90
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $string ) = @_; |
91
|
0
|
|
|
|
|
0
|
return _croak('Not Implemented'); |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub load_filehandle { |
96
|
7
|
|
|
7
|
1
|
47150
|
my ( $self, $fh ) = @_; |
97
|
|
|
|
|
|
|
|
98
|
7
|
|
|
|
|
58
|
$TYPE_FILEHANDLE->assert_valid($fh); |
99
|
7
|
|
|
|
|
5817
|
require String::Sections::Result; |
100
|
7
|
|
|
|
|
51
|
my $result_ob = String::Sections::Result->new(); |
101
|
|
|
|
|
|
|
|
102
|
7
|
100
|
|
|
|
16737
|
if ( $self->default_name ) { |
103
|
2
|
|
|
|
|
1398
|
$result_ob->set_current( $self->default_name ); |
104
|
2
|
|
|
|
|
1279
|
$result_ob->append_data_to_current_section(); |
105
|
|
|
|
|
|
|
} |
106
|
7
|
|
|
|
|
426
|
while ( defined( my $line = <$fh> ) ) { |
107
|
24
|
|
|
|
|
97
|
my $result = $self->__add_line( $result_ob, \$line, ); |
108
|
24
|
50
|
|
|
|
229
|
next if $result; |
109
|
0
|
0
|
|
|
|
0
|
last if not $result; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
7
|
|
|
|
|
49
|
return $result_ob; |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# |
117
|
|
|
|
|
|
|
# Defines accessors *_regex and _*_regex , that are for public and private access respectively. |
118
|
|
|
|
|
|
|
# Defaults to _default_*_regex. |
119
|
|
|
|
|
|
|
# |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub _regex_type { |
123
|
60
|
|
|
60
|
|
149
|
my $name = shift; |
124
|
60
|
|
|
|
|
688
|
return ( is => 'ro', isa => $TYPE_REGEXP, builder => '_default_' . $name, lazy => 1 ); |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub _string_type { |
129
|
15
|
|
|
15
|
|
41
|
my $name = shift; |
130
|
15
|
|
|
|
|
133
|
return ( is => 'ro', isa => $TYPE_OPTIONAL_STRING, builder => '_default_' . $name, lazy => 1 ); |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub _boolean_type { |
135
|
45
|
|
|
45
|
|
103
|
my $name = shift; |
136
|
45
|
|
|
|
|
436
|
return ( is => 'ro', isa => $TYPE_BOOL, builder => '_default_' . $name, lazy => 1 ); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
has 'header_regex' => _regex_type('header_regex'); |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
has 'empty_line_regex' => _regex_type('empty_line_regex'); |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
has 'document_end_regex' => _regex_type('document_end_regex'); |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
has 'line_escape_regex' => _regex_type('line_escape_regex'); |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
has 'default_name' => _string_type('default_name'); |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# Boolean Accessors |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
has 'stop_at_end' => _boolean_type('stop_at_end'); |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
has 'ignore_empty_prelude' => _boolean_type('ignore_empty_prelude'); |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
has 'enable_escapes' => _boolean_type('enable_escapes'); |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# Default values for various attributes. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub _default_header_regex { |
169
|
13
|
|
|
13
|
|
9048
|
return qr{ |
170
|
|
|
|
|
|
|
\A # start |
171
|
|
|
|
|
|
|
_+\[ # __[ |
172
|
|
|
|
|
|
|
\s* # any whitespace |
173
|
|
|
|
|
|
|
([^\]]+?) # this is the actual name of the section |
174
|
|
|
|
|
|
|
\s* # any whitespace |
175
|
|
|
|
|
|
|
\]_+ # ]__ |
176
|
|
|
|
|
|
|
[\x0d\x0a]{1,2} # possible cariage return for windows files |
177
|
|
|
|
|
|
|
\z # end |
178
|
|
|
|
|
|
|
}msx; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub _default_empty_line_regex { |
183
|
0
|
|
|
0
|
|
0
|
return qr{ |
184
|
|
|
|
|
|
|
^ |
185
|
|
|
|
|
|
|
\s* # Any empty lines before the first section get ignored. |
186
|
|
|
|
|
|
|
$ |
187
|
|
|
|
|
|
|
}msx; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
sub _default_document_end_regex { |
192
|
0
|
|
|
0
|
|
0
|
return qr{ |
193
|
|
|
|
|
|
|
^ # Start of line |
194
|
|
|
|
|
|
|
__END__ # Document END matcher |
195
|
|
|
|
|
|
|
}msx; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub _default_line_escape_regex { |
200
|
0
|
|
|
0
|
|
0
|
return qr{ |
201
|
|
|
|
|
|
|
\A # Start of line |
202
|
|
|
|
|
|
|
\\ # A literal \ |
203
|
|
|
|
|
|
|
}msx; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
|
207
|
11
|
|
|
11
|
|
7597
|
sub _default_default_name { return } |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
|
210
|
11
|
|
|
11
|
|
7043
|
sub _default_stop_at_end { return } |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
|
213
|
11
|
|
|
11
|
|
13094
|
sub _default_ignore_empty_prelude { return 1 } |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
|
216
|
11
|
|
|
11
|
|
8266
|
sub _default_enable_escapes { return } |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
1; |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
__END__ |