line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
4
|
|
|
4
|
|
20
|
use strict; |
|
4
|
|
|
|
|
5
|
|
|
4
|
|
|
|
|
91
|
|
2
|
4
|
|
|
4
|
|
18
|
use warnings; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
153
|
|
3
|
|
|
|
|
|
|
package Pod::Eventual 0.094003; |
4
|
|
|
|
|
|
|
# ABSTRACT: read a POD document as a series of trivial events |
5
|
4
|
|
|
4
|
|
1761
|
use Mixin::Linewise::Readers 0.102; |
|
4
|
|
|
|
|
83473
|
|
|
4
|
|
|
|
|
18
|
|
6
|
|
|
|
|
|
|
|
7
|
4
|
|
|
4
|
|
1347
|
use Carp (); |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
1981
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#pod =head1 SYNOPSIS |
10
|
|
|
|
|
|
|
#pod |
11
|
|
|
|
|
|
|
#pod package Your::Pod::Parser; |
12
|
|
|
|
|
|
|
#pod use base 'Pod::Eventual'; |
13
|
|
|
|
|
|
|
#pod |
14
|
|
|
|
|
|
|
#pod sub handle_event { |
15
|
|
|
|
|
|
|
#pod my ($self, $event) = @_; |
16
|
|
|
|
|
|
|
#pod |
17
|
|
|
|
|
|
|
#pod print Dumper($event); |
18
|
|
|
|
|
|
|
#pod } |
19
|
|
|
|
|
|
|
#pod |
20
|
|
|
|
|
|
|
#pod =head1 DESCRIPTION |
21
|
|
|
|
|
|
|
#pod |
22
|
|
|
|
|
|
|
#pod POD is a pretty simple format to write, but it can be a big pain to deal with |
23
|
|
|
|
|
|
|
#pod reading it and doing anything useful with it. Most existing POD parsers care |
24
|
|
|
|
|
|
|
#pod about semantics, like whether a C<=item> occurred after an C<=over> but before |
25
|
|
|
|
|
|
|
#pod a C, figuring out how to link a C<< LEE >>, and other things like |
26
|
|
|
|
|
|
|
#pod that. |
27
|
|
|
|
|
|
|
#pod |
28
|
|
|
|
|
|
|
#pod Pod::Eventual is much less ambitious and much more stupid. Fortunately, stupid |
29
|
|
|
|
|
|
|
#pod is often better. (That's what I keep telling myself, anyway.) |
30
|
|
|
|
|
|
|
#pod |
31
|
|
|
|
|
|
|
#pod Pod::Eventual reads line-based input and produces events describing each POD |
32
|
|
|
|
|
|
|
#pod paragraph or directive it finds. Once complete events are immediately passed |
33
|
|
|
|
|
|
|
#pod to the C method. This method should be implemented by |
34
|
|
|
|
|
|
|
#pod Pod::Eventual subclasses. If it isn't, Pod::Eventual's own C |
35
|
|
|
|
|
|
|
#pod will be called, and will raise an exception. |
36
|
|
|
|
|
|
|
#pod |
37
|
|
|
|
|
|
|
#pod =head1 EVENTS |
38
|
|
|
|
|
|
|
#pod |
39
|
|
|
|
|
|
|
#pod There are four kinds of events that Pod::Eventual will produce. All are |
40
|
|
|
|
|
|
|
#pod represented as hash references. |
41
|
|
|
|
|
|
|
#pod |
42
|
|
|
|
|
|
|
#pod =head2 Command Events |
43
|
|
|
|
|
|
|
#pod |
44
|
|
|
|
|
|
|
#pod These events represent commands -- those things that start with an equals sign |
45
|
|
|
|
|
|
|
#pod in the first column. Here are some examples of POD and the event that would be |
46
|
|
|
|
|
|
|
#pod produced. |
47
|
|
|
|
|
|
|
#pod |
48
|
|
|
|
|
|
|
#pod A simple header: |
49
|
|
|
|
|
|
|
#pod |
50
|
|
|
|
|
|
|
#pod =head1 NAME |
51
|
|
|
|
|
|
|
#pod |
52
|
|
|
|
|
|
|
#pod { type => 'command', command => 'head1', content => "NAME\n", start_line => 4 } |
53
|
|
|
|
|
|
|
#pod |
54
|
|
|
|
|
|
|
#pod Notice that the content includes the trailing newline. That's to maintain |
55
|
|
|
|
|
|
|
#pod similarity with this possibly-surprising case: |
56
|
|
|
|
|
|
|
#pod |
57
|
|
|
|
|
|
|
#pod =for HTML |
58
|
|
|
|
|
|
|
#pod We're actually still in the command event, here. |
59
|
|
|
|
|
|
|
#pod |
60
|
|
|
|
|
|
|
#pod { |
61
|
|
|
|
|
|
|
#pod type => 'command', |
62
|
|
|
|
|
|
|
#pod command => 'for', |
63
|
|
|
|
|
|
|
#pod content => "HTML\nWe're actually still in the command event, here.\n", |
64
|
|
|
|
|
|
|
#pod start_line => 8, |
65
|
|
|
|
|
|
|
#pod } |
66
|
|
|
|
|
|
|
#pod |
67
|
|
|
|
|
|
|
#pod Pod::Eventual does not care what the command is. It doesn't keep track of what |
68
|
|
|
|
|
|
|
#pod it's seen or whether you've used a command that isn't defined. The only |
69
|
|
|
|
|
|
|
#pod special case is C<=cut>, which is never more than one line. |
70
|
|
|
|
|
|
|
#pod |
71
|
|
|
|
|
|
|
#pod =cut |
72
|
|
|
|
|
|
|
#pod We are no longer parsing POD when this line is read. |
73
|
|
|
|
|
|
|
#pod |
74
|
|
|
|
|
|
|
#pod { |
75
|
|
|
|
|
|
|
#pod type => 'command', |
76
|
|
|
|
|
|
|
#pod command => 'cut', |
77
|
|
|
|
|
|
|
#pod content => "\n", |
78
|
|
|
|
|
|
|
#pod start_line => 15, |
79
|
|
|
|
|
|
|
#pod } |
80
|
|
|
|
|
|
|
#pod |
81
|
|
|
|
|
|
|
#pod Waiving this special case may be an option in the future. |
82
|
|
|
|
|
|
|
#pod |
83
|
|
|
|
|
|
|
#pod =head2 Text Events |
84
|
|
|
|
|
|
|
#pod |
85
|
|
|
|
|
|
|
#pod A text event is just a paragraph of text, beginning after one or more empty |
86
|
|
|
|
|
|
|
#pod lines and running until the next empty line (or F<=cut>). In Perl 5's standard |
87
|
|
|
|
|
|
|
#pod usage of Pod, text content that begins with whitespace is a "verbatim" |
88
|
|
|
|
|
|
|
#pod paragraph, and text content that begins with non-whitespace is an "ordinary" |
89
|
|
|
|
|
|
|
#pod paragraph. |
90
|
|
|
|
|
|
|
#pod |
91
|
|
|
|
|
|
|
#pod Pod::Eventual doesn't care. |
92
|
|
|
|
|
|
|
#pod |
93
|
|
|
|
|
|
|
#pod Text events look like this: |
94
|
|
|
|
|
|
|
#pod |
95
|
|
|
|
|
|
|
#pod { |
96
|
|
|
|
|
|
|
#pod type => 'text', |
97
|
|
|
|
|
|
|
#pod content => "a string of text ending with a\n", |
98
|
|
|
|
|
|
|
#pod start_line => 16, |
99
|
|
|
|
|
|
|
#pod } |
100
|
|
|
|
|
|
|
#pod |
101
|
|
|
|
|
|
|
#pod =head2 Blank events |
102
|
|
|
|
|
|
|
#pod |
103
|
|
|
|
|
|
|
#pod These events represent blank lines (or many blank lines) within a Pod section. |
104
|
|
|
|
|
|
|
#pod |
105
|
|
|
|
|
|
|
#pod Blank events look like this: |
106
|
|
|
|
|
|
|
#pod |
107
|
|
|
|
|
|
|
#pod { |
108
|
|
|
|
|
|
|
#pod type => 'blank', |
109
|
|
|
|
|
|
|
#pod content => "\n\n\n\n", |
110
|
|
|
|
|
|
|
#pod start_line => 21, |
111
|
|
|
|
|
|
|
#pod } |
112
|
|
|
|
|
|
|
#pod |
113
|
|
|
|
|
|
|
#pod =head2 Non-Pod events |
114
|
|
|
|
|
|
|
#pod |
115
|
|
|
|
|
|
|
#pod These events represent non-Pod segments of the input. |
116
|
|
|
|
|
|
|
#pod |
117
|
|
|
|
|
|
|
#pod Non-Pod events look like this: |
118
|
|
|
|
|
|
|
#pod |
119
|
|
|
|
|
|
|
#pod { |
120
|
|
|
|
|
|
|
#pod type => 'nonpod', |
121
|
|
|
|
|
|
|
#pod content => "#!/usr/bin/perl\nuse strict;\n\nuse Acme::ProgressBar\n\n", |
122
|
|
|
|
|
|
|
#pod start_line => 1, |
123
|
|
|
|
|
|
|
#pod } |
124
|
|
|
|
|
|
|
#pod |
125
|
|
|
|
|
|
|
#pod =method read_handle |
126
|
|
|
|
|
|
|
#pod |
127
|
|
|
|
|
|
|
#pod Pod::Eventual->read_handle($io_handle, \%arg); |
128
|
|
|
|
|
|
|
#pod |
129
|
|
|
|
|
|
|
#pod This method iterates through the lines of a handle, producing events and |
130
|
|
|
|
|
|
|
#pod calling the C method. |
131
|
|
|
|
|
|
|
#pod |
132
|
|
|
|
|
|
|
#pod The only valid argument in C<%arg> (for now) is C, which indicates |
133
|
|
|
|
|
|
|
#pod whether we should assume that we are parsing pod when we start parsing the |
134
|
|
|
|
|
|
|
#pod file. By default, this is false. |
135
|
|
|
|
|
|
|
#pod |
136
|
|
|
|
|
|
|
#pod This is useful to behave differently when reading a F<.pm> or F<.pod> file. |
137
|
|
|
|
|
|
|
#pod |
138
|
|
|
|
|
|
|
#pod B the handle is expected to have an encoding layer so that it will |
139
|
|
|
|
|
|
|
#pod return text, not bytes, on reads. |
140
|
|
|
|
|
|
|
#pod |
141
|
|
|
|
|
|
|
#pod =method read_file |
142
|
|
|
|
|
|
|
#pod |
143
|
|
|
|
|
|
|
#pod This behaves just like C, but expects a filename rather than a |
144
|
|
|
|
|
|
|
#pod handle. The file will be assumed to be UTF-8 encoded. |
145
|
|
|
|
|
|
|
#pod |
146
|
|
|
|
|
|
|
#pod =method read_string |
147
|
|
|
|
|
|
|
#pod |
148
|
|
|
|
|
|
|
#pod This behaves just like C, but expects a string containing POD |
149
|
|
|
|
|
|
|
#pod text rather than a handle. |
150
|
|
|
|
|
|
|
#pod |
151
|
|
|
|
|
|
|
#pod =cut |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub read_handle { |
154
|
4
|
|
|
4
|
1
|
12
|
my ($self, $handle, $arg) = @_; |
155
|
4
|
|
50
|
|
|
23
|
$arg ||= {}; |
156
|
|
|
|
|
|
|
|
157
|
4
|
50
|
|
|
|
13
|
my $in_pod = $arg->{in_pod} ? 1 : 0; |
158
|
4
|
|
|
|
|
8
|
my $current; |
159
|
|
|
|
|
|
|
|
160
|
4
|
|
|
|
|
147
|
LINE: while (my $line = $handle->getline) { |
161
|
78
|
100
|
100
|
|
|
2086
|
if ($in_pod and $line =~ /^=cut(?:\s*)(.*?)(\n)\z/) { |
162
|
4
|
|
|
|
|
11
|
my $content = "$1$2"; |
163
|
4
|
|
|
|
|
7
|
$in_pod = 0; |
164
|
4
|
50
|
|
|
|
18
|
$self->handle_event($current) if $current; |
165
|
4
|
|
|
|
|
8
|
undef $current; |
166
|
4
|
|
|
|
|
11
|
$self->handle_event({ |
167
|
|
|
|
|
|
|
type => 'command', |
168
|
|
|
|
|
|
|
command => 'cut', |
169
|
|
|
|
|
|
|
content => $content, |
170
|
|
|
|
|
|
|
start_line => $handle->input_line_number, |
171
|
|
|
|
|
|
|
}); |
172
|
4
|
|
|
|
|
60
|
next LINE; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
74
|
100
|
|
|
|
156
|
if ($line =~ /\A=[a-z]/i) { |
176
|
8
|
100
|
100
|
|
|
29
|
if ($current and not $in_pod) { |
177
|
4
|
|
|
|
|
15
|
$self->handle_nonpod($current); |
178
|
4
|
|
|
|
|
7
|
undef $current; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
8
|
|
|
|
|
12
|
$in_pod = 1; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
74
|
100
|
|
|
|
112
|
if (not $in_pod) { |
185
|
17
|
|
100
|
|
|
51
|
$current ||= { |
186
|
|
|
|
|
|
|
type => 'nonpod', |
187
|
|
|
|
|
|
|
start_line => $handle->input_line_number, |
188
|
|
|
|
|
|
|
content => '', |
189
|
|
|
|
|
|
|
}; |
190
|
|
|
|
|
|
|
|
191
|
17
|
|
|
|
|
130
|
$current->{content} .= $line; |
192
|
17
|
|
|
|
|
244
|
next LINE; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
57
|
100
|
100
|
|
|
190
|
if ($line =~ /^\s*$/) { |
|
|
100
|
|
|
|
|
|
196
|
25
|
100
|
66
|
|
|
88
|
if ($current and $current->{type} ne 'blank') { |
197
|
23
|
|
|
|
|
53
|
$self->handle_event($current); |
198
|
|
|
|
|
|
|
|
199
|
23
|
|
|
|
|
46
|
$current = { |
200
|
|
|
|
|
|
|
type => 'blank', |
201
|
|
|
|
|
|
|
content => '', |
202
|
|
|
|
|
|
|
start_line => $handle->input_line_number, |
203
|
|
|
|
|
|
|
}; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
} elsif ($current and $current->{type} eq 'blank') { |
206
|
20
|
|
|
|
|
49
|
$self->handle_blank($current); |
207
|
20
|
|
|
|
|
23
|
undef $current; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
57
|
100
|
|
|
|
360
|
if ($current) { |
211
|
32
|
|
|
|
|
51
|
$current->{content} .= $line; |
212
|
32
|
|
|
|
|
494
|
next LINE; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
25
|
100
|
|
|
|
75
|
if ($line =~ /^=([a-z]+\S*)(?:\s*)(.*?)(\n)\z/i) { |
216
|
8
|
|
|
|
|
17
|
my $command = $1; |
217
|
8
|
|
|
|
|
21
|
my $content = "$2$3"; |
218
|
8
|
|
|
|
|
26
|
$current = { |
219
|
|
|
|
|
|
|
type => 'command', |
220
|
|
|
|
|
|
|
command => $command, |
221
|
|
|
|
|
|
|
content => $content, |
222
|
|
|
|
|
|
|
start_line => $handle->input_line_number, |
223
|
|
|
|
|
|
|
}; |
224
|
8
|
|
|
|
|
241
|
next LINE; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
$current = { |
228
|
17
|
|
|
|
|
34
|
type => 'text', |
229
|
|
|
|
|
|
|
content => $line, |
230
|
|
|
|
|
|
|
start_line => $handle->input_line_number, |
231
|
|
|
|
|
|
|
}; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
4
|
100
|
|
|
|
122
|
if ($current) { |
235
|
|
|
|
|
|
|
my $method = $current->{type} eq 'blank' ? 'handle_blank' |
236
|
2
|
50
|
|
|
|
9
|
: $current->{type} eq 'nonpod' ? 'handle_nonpod' |
|
|
100
|
|
|
|
|
|
237
|
|
|
|
|
|
|
: 'handle_event'; |
238
|
|
|
|
|
|
|
|
239
|
2
|
50
|
|
|
|
10
|
$self->$method($current) if $current; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
4
|
|
|
|
|
11
|
return; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
#pod =method handle_event |
246
|
|
|
|
|
|
|
#pod |
247
|
|
|
|
|
|
|
#pod This method is called each time Pod::Eventual finishes scanning for a new POD |
248
|
|
|
|
|
|
|
#pod event. It must be implemented by a subclass or it will raise an exception. |
249
|
|
|
|
|
|
|
#pod |
250
|
|
|
|
|
|
|
#pod =cut |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub handle_event { |
253
|
0
|
|
|
0
|
1
|
|
Carp::confess("handle_event not implemented by $_[0]"); |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
#pod =method handle_nonpod |
257
|
|
|
|
|
|
|
#pod |
258
|
|
|
|
|
|
|
#pod This method is called each time a non-POD segment is seen -- that is, lines |
259
|
|
|
|
|
|
|
#pod after C<=cut> and before another command. |
260
|
|
|
|
|
|
|
#pod |
261
|
|
|
|
|
|
|
#pod If unimplemented by a subclass, it does nothing by default. |
262
|
|
|
|
|
|
|
#pod |
263
|
|
|
|
|
|
|
#pod =cut |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
0
|
1
|
|
sub handle_nonpod { } |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
#pod =method handle_blank |
268
|
|
|
|
|
|
|
#pod |
269
|
|
|
|
|
|
|
#pod This method is called at the end of a sequence of one or more blank lines. |
270
|
|
|
|
|
|
|
#pod |
271
|
|
|
|
|
|
|
#pod If unimplemented by a subclass, it does nothing by default. |
272
|
|
|
|
|
|
|
#pod |
273
|
|
|
|
|
|
|
#pod =cut |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
0
|
1
|
|
sub handle_blank { } |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
1; |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
__END__ |