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