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