xref: /openbsd-src/gnu/usr.bin/perl/cpan/Pod-Simple/lib/Pod/Simple/JustPod.pm (revision a0747c9f67a4ae71ccb71e62a28d1ea19e06a63c)
1use 5;
2package Pod::Simple::JustPod;
3# ABSTRACT: Pod::Simple formatter that extracts POD from a file containing
4#           other things as well
5use strict;
6use warnings;
7
8use Pod::Simple::Methody ();
9our @ISA = ('Pod::Simple::Methody');
10
11sub new {
12  my $self = shift;
13  my $new  = $self->SUPER::new(@_);
14
15  $new->accept_targets('*');
16  $new->keep_encoding_directive(1);
17  $new->preserve_whitespace(1);
18  $new->complain_stderr(1);
19  $new->_output_is_for_JustPod(1);
20
21  return $new;
22}
23
24#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25
26sub check_that_all_is_closed {
27
28  # Actually checks that the things we depend on being balanced in fact are,
29  # so that we can continue in spit of pod errors
30
31  my $self = shift;
32  while ($self->{inL}) {
33    $self->end_L(@_);
34  }
35  while ($self->{fcode_end} && @{$self->{fcode_end}}) {
36    $self->_end_fcode(@_);
37  }
38}
39
40sub handle_text {
41
42  # Add text to the output buffer.  This is skipped if within a L<>, as we use
43  # the 'raw' attribute of that tag instead.
44
45  $_[0]{buffer} .= $_[1] unless $_[0]{inL} ;
46}
47
48sub spacer {
49
50  # Prints the white space following things like =head1.  This is normally a
51  # blank, unless BlackBox has told us otherwise.
52
53  my ($self, $arg) = @_;
54  return unless $arg;
55
56  my $spacer = ($arg->{'~orig_spacer'})
57                ? $arg->{'~orig_spacer'}
58                : " ";
59  $self->handle_text($spacer);
60}
61
62sub _generic_start {
63
64  # Called from tags like =head1, etc.
65
66  my ($self, $text, $arg) = @_;
67  $self->check_that_all_is_closed();
68  $self->handle_text($text);
69  $self->spacer($arg);
70}
71
72sub start_Document    { shift->_generic_start("=pod\n\n"); }
73sub start_head1       { shift->_generic_start('=head1', @_); }
74sub start_head2       { shift->_generic_start('=head2', @_); }
75sub start_head3       { shift->_generic_start('=head3', @_); }
76sub start_head4       { shift->_generic_start('=head4', @_); }
77sub start_encoding    { shift->_generic_start('=encoding', @_); }
78# sub start_Para
79# sub start_Verbatim
80
81sub start_item_bullet { # Handle =item *
82  my ($self, $arg) = @_;
83  $self->check_that_all_is_closed();
84  $self->handle_text('=item');
85
86  # It can be that they said simply '=item', and it is inferred that it is to
87  # be a bullet.
88  if (! $arg->{'~orig_content'}) {
89    $self->handle_text("\n\n");
90  }
91  else {
92    $self->spacer($arg);
93    if ($arg->{'~_freaky_para_hack'}) {
94
95        # See Message Id <87y3gtcwa2.fsf@hope.eyrie.org>
96        my $item_text = $arg->{'~orig_content'};
97        my $trailing = quotemeta $arg->{'~_freaky_para_hack'};
98        $item_text =~ s/$trailing$//;
99        $self->handle_text($item_text);
100    }
101    else {
102        $self->handle_text("*\n\n");
103    }
104  }
105}
106
107sub start_item_number {     # Handle '=item 2'
108  my ($self, $arg) = @_;
109  $self->check_that_all_is_closed();
110  $self->handle_text("=item");
111  $self->spacer($arg);
112  $self->handle_text("$arg->{'~orig_content'}\n\n");
113}
114
115sub start_item_text {   # Handle '=item foo bar baz'
116  my ($self, $arg) = @_;
117  $self->check_that_all_is_closed();
118  $self->handle_text('=item');
119  $self->spacer($arg);
120}
121
122sub _end_item {
123  my $self = shift;
124  $self->check_that_all_is_closed();
125  $self->emit;
126}
127
128*end_item_bullet = *_end_item;
129*end_item_number = *_end_item;
130*end_item_text   = *_end_item;
131
132sub _start_over  {  # Handle =over
133  my ($self, $arg) = @_;
134  $self->check_that_all_is_closed();
135  $self->handle_text("=over");
136
137  # The =over amount is optional
138  if ($arg->{'~orig_content'}) {
139    $self->spacer($arg);
140    $self->handle_text("$arg->{'~orig_content'}");
141  }
142  $self->handle_text("\n\n");
143}
144
145*start_over_bullet = *_start_over;
146*start_over_number = *_start_over;
147*start_over_text   = *_start_over;
148*start_over_block  = *_start_over;
149
150sub _end_over  {
151  my $self = shift;
152  $self->check_that_all_is_closed();
153  $self->handle_text('=back');
154  $self->emit;
155}
156
157*end_over_bullet = *_end_over;
158*end_over_number = *_end_over;
159*end_over_text   = *_end_over;
160*end_over_block  = *_end_over;
161
162sub end_Document    {
163  my $self = shift;
164  $self->emit;        # Make sure buffer gets flushed
165  print {$self->{'output_fh'} } "=cut\n"
166}
167
168sub _end_generic  {
169  my $self = shift;
170  $self->check_that_all_is_closed();
171  $self->emit;
172}
173
174*end_head1    = *_end_generic;
175*end_head2    = *_end_generic;
176*end_head3    = *_end_generic;
177*end_head4    = *_end_generic;
178*end_encoding = *_end_generic;
179*end_Para     = *_end_generic;
180*end_Verbatim = *_end_generic;
181
182sub _start_fcode {
183  my ($type, $self, $flags) = @_;
184
185  # How many brackets is set by BlackBox unless the count is 1
186  my $bracket_count = (exists $flags->{'~bracket_count'})
187                       ? $flags->{'~bracket_count'}
188                       : 1;
189  $self->handle_text($type . ( "<" x $bracket_count));
190
191  my $rspacer = "";
192  if ($bracket_count > 1) {
193    my $lspacer = (exists $flags->{'~lspacer'})
194                  ? $flags->{'~lspacer'}
195                  : " ";
196    $self->handle_text($lspacer);
197
198    $rspacer = (exists $flags->{'~rspacer'})
199                  ? $flags->{'~rspacer'}
200                  : " ";
201  }
202
203  # BlackBox doesn't output things for for the ending code callbacks, so save
204  # what we need.
205  push @{$self->{'fcode_end'}}, [ $bracket_count, $rspacer ];
206}
207
208sub start_B { _start_fcode('B', @_); }
209sub start_C { _start_fcode('C', @_); }
210sub start_E { _start_fcode('E', @_); }
211sub start_F { _start_fcode('F', @_); }
212sub start_I { _start_fcode('I', @_); }
213sub start_S { _start_fcode('S', @_); }
214sub start_X { _start_fcode('X', @_); }
215sub start_Z { _start_fcode('Z', @_); }
216
217sub _end_fcode {
218    my $self = shift;
219    my $fcode_end = pop @{$self->{'fcode_end'}};
220    my $bracket_count = 1;
221    my $rspacer = "";
222
223    if (! defined $fcode_end) { # If BlackBox is working, this shouldn't
224                                # happen, but verify
225      $self->whine($self->{line_count}, "Extra '>'");
226    }
227    else {
228      $bracket_count = $fcode_end->[0];
229      $rspacer = $fcode_end->[1];
230    }
231
232    $self->handle_text($rspacer) if $bracket_count > 1;
233    $self->handle_text(">" x $bracket_count);
234}
235
236*end_B   = *_end_fcode;
237*end_C   = *_end_fcode;
238*end_E   = *_end_fcode;
239*end_F   = *_end_fcode;
240*end_I   = *_end_fcode;
241*end_S   = *_end_fcode;
242*end_X   = *_end_fcode;
243*end_Z   = *_end_fcode;
244
245sub start_L {
246    _start_fcode('L', @_);
247    $_[0]->handle_text($_[1]->{raw});
248    $_[0]->{inL}++
249}
250
251sub end_L {
252  my $self = shift;
253  $self->{inL}--;
254  if ($self->{inL} < 0) {   # If BlackBox is working, this shouldn't
255                            # happen, but verify
256    $self->whine($self->{line_count}, "Extra '>' ending L<>");
257    $self->{inL} = 0;
258  }
259
260  $self->_end_fcode(@_);
261}
262
263sub emit {
264  my $self = shift;
265
266  if ($self->{buffer} ne "") {
267    print { $self->{'output_fh'} } "",$self->{buffer} ,"\n\n";
268
269    $self->{buffer} = "";
270  }
271
272  return;
273}
274
2751;
276
277__END__
278
279=head1 NAME
280
281Pod::Simple::JustPod -- just the Pod, the whole Pod, and nothing but the Pod
282
283=head1 SYNOPSIS
284
285 my $infile  = "mixed_code_and_pod.pm";
286 my $outfile = "just_the_pod.pod";
287 open my $fh, ">$outfile" or die "Can't write to $outfile: $!";
288
289 my $parser = Pod::Simple::JustPod->new();
290 $parser->output_fh($fh);
291 $parser->parse_file($infile);
292 close $fh or die "Can't close $outfile: $!";
293
294=head1 DESCRIPTION
295
296This class returns a copy of its input, translated into Perl's internal
297encoding (UTF-8), and with all the non-Pod lines removed.
298
299This is a subclass of L<Pod::Simple::Methody> and inherits all its methods.
300And since, that in turn is a subclass of L<Pod::Simple>, you can use any of
301its methods.  This means you can output to a string instead of a file, or
302you can parse from an array.
303
304This class strives to return the Pod lines of the input completely unchanged,
305except for any necessary translation into Perl's internal encoding, and it makes
306no effort to return trailing spaces on lines; these likely will be stripped.
307If the input pod is well-formed with no warnings nor errors generated, the
308extracted pod should generate the same documentation when formatted by a Pod
309formatter as the original file does.
310
311By default, warnings are output to STDERR
312
313=head1 SEE ALSO
314
315L<Pod::Simple>, L<Pod::Simple::Methody>
316
317=head1 SUPPORT
318
319Questions or discussion about POD and Pod::Simple should be sent to the
320L<mailto:pod-people@perl.org> mail list. Send an empty email to
321L<mailto:pod-people-subscribe@perl.org> to subscribe.
322
323This module is managed in an open GitHub repository,
324L<https://github.com/theory/pod-simple/>. Feel free to fork and contribute, or
325to clone L<git://github.com/theory/pod-simple.git> and send patches!
326
327Patches against Pod::Simple are welcome. Please send bug reports to
328L<mailto:<bug-pod-simple@rt.cpan.org>.
329
330=head1 COPYRIGHT AND DISCLAIMERS
331
332Copyright (c) 2002 Sean M. Burke.
333
334This library is free software; you can redistribute it and/or modify it
335under the same terms as Perl itself.
336
337This program is distributed in the hope that it will be useful, but
338without any warranty; without even the implied warranty of
339merchantability or fitness for a particular purpose.
340
341=head1 AUTHOR
342
343Pod::Simple was created by Sean M. Burke <sburke@cpan.org>.
344But don't bother him, he's retired.
345
346Pod::Simple is maintained by:
347
348=over
349
350=item * Allison Randal C<allison@perl.org>
351
352=item * Hans Dieter Pearcey C<hdp@cpan.org>
353
354=item * David E. Wheeler C<dwheeler@cpan.org>
355
356=back
357
358Pod::Simple::JustPod was developed by John SJ Anderson
359C<genehack@genehack.org>, with contributions from Karl Williamson
360C<khw@cpan.org>.
361
362=cut
363