1package Module::Install::ReadmeFromPod; 2 3use 5.006; 4use strict; 5use warnings; 6use base qw(Module::Install::Base); 7use vars qw($VERSION); 8 9$VERSION = '0.30'; 10 11{ 12 13 # these aren't defined until after _require_admin is run, so 14 # define them so prototypes are available during compilation. 15 sub io; 16 sub capture(&;@); 17 18=pod 19 20=begin quiet_pod_coverage 21 22=head2 io 23 24=head2 capture 25 26=end quiet_pod_coverage 27 28=cut 29 30 my $done = 0; 31 32 sub _require_admin { 33 34 # do this once to avoid redefinition warnings from IO::All 35 return if $done; 36 37 require IO::All; 38 IO::All->import( '-binary' ); 39 40 require Capture::Tiny; 41 Capture::Tiny->import ( 'capture' ); 42 43 return; 44 } 45 46} 47 48sub readme_from { 49 my $self = shift; 50 return unless $self->is_admin; 51 52 _require_admin; 53 54 # Input file 55 my $in_file = shift || $self->_all_from 56 or die "Can't determine file to make readme_from"; 57 58 # Get optional arguments 59 my ($clean, $format, $out_file, $options); 60 my $args = shift; 61 if ( ref $args ) { 62 # Arguments are in a hashref 63 if ( ref($args) ne 'HASH' ) { 64 die "Expected a hashref but got a ".ref($args)."\n"; 65 } else { 66 $clean = $args->{'clean'}; 67 $format = $args->{'format'}; 68 $out_file = $args->{'output_file'}; 69 $options = $args->{'options'}; 70 } 71 } else { 72 # Arguments are in a list 73 $clean = $args; 74 $format = shift; 75 $out_file = shift; 76 $options = \@_; 77 } 78 79 # Default values; 80 $clean ||= 0; 81 $format ||= 'txt'; 82 83 # Generate README 84 print "readme_from $in_file to $format\n"; 85 if ($format =~ m/te?xt/) { 86 $out_file = $self->_readme_txt($in_file, $out_file, $options); 87 } elsif ($format =~ m/html?/) { 88 $out_file = $self->_readme_htm($in_file, $out_file, $options); 89 } elsif ($format eq 'man') { 90 $out_file = $self->_readme_man($in_file, $out_file, $options); 91 } elsif ($format eq 'md') { 92 $out_file = $self->_readme_md($in_file, $out_file, $options); 93 } elsif ($format eq 'pdf') { 94 $out_file = $self->_readme_pdf($in_file, $out_file, $options); 95 } 96 97 if ($clean) { 98 $self->clean_files($out_file); 99 } 100 101 return 1; 102} 103 104 105sub _readme_txt { 106 my ($self, $in_file, $out_file, $options) = @_; 107 $out_file ||= 'README'; 108 require Pod::Text; 109 my $parser = Pod::Text->new( @$options ); 110 my $io = io->file($out_file)->open(">"); 111 my $out_fh = $io->io_handle; 112 $parser->output_fh( *$out_fh ); 113 $parser->parse_file( $in_file ); 114 return $out_file; 115} 116 117 118sub _readme_htm { 119 my ($self, $in_file, $out_file, $options) = @_; 120 $out_file ||= 'README.htm'; 121 require Pod::Html; 122 my ($o) = capture { 123 Pod::Html::pod2html( 124 "--infile=$in_file", 125 "--outfile=-", 126 @$options, 127 ); 128 }; 129 io->file($out_file)->print($o); 130 # Remove temporary files if needed 131 for my $file ('pod2htmd.tmp', 'pod2htmi.tmp') { 132 if (-e $file) { 133 unlink $file or warn "Warning: Could not remove file '$file'.\n$!\n"; 134 } 135 } 136 return $out_file; 137} 138 139 140sub _readme_man { 141 my ($self, $in_file, $out_file, $options) = @_; 142 $out_file ||= 'README.1'; 143 require Pod::Man; 144 my $parser = Pod::Man->new( @$options ); 145 my $io = io->file($out_file)->open(">"); 146 my $out_fh = $io->io_handle; 147 $parser->output_fh( *$out_fh ); 148 $parser->parse_file( $in_file ); 149 return $out_file; 150} 151 152 153sub _readme_pdf { 154 my ($self, $in_file, $out_file, $options) = @_; 155 $out_file ||= 'README.pdf'; 156 eval { require App::pod2pdf; } 157 or die "Could not generate $out_file because pod2pdf could not be found\n"; 158 my $parser = App::pod2pdf->new( @$options ); 159 $parser->parse_from_file($in_file); 160 my ($o) = capture { $parser->output }; 161 io->file($out_file)->print($o); 162 return $out_file; 163} 164 165sub _readme_md { 166 my ($self, $in_file, $out_file, $options) = @_; 167 $out_file ||= 'README.md'; 168 require Pod::Markdown; 169 my $parser = Pod::Markdown->new( @$options ); 170 my $io = io->file($out_file)->open(">"); 171 my $out_fh = $io->io_handle; 172 $parser->output_fh( *$out_fh ); 173 $parser->parse_file( $in_file ); 174 return $out_file; 175} 176 177 178sub _all_from { 179 my $self = shift; 180 return unless $self->admin->{extensions}; 181 my ($metadata) = grep { 182 ref($_) eq 'Module::Install::Metadata'; 183 } @{$self->admin->{extensions}}; 184 return unless $metadata; 185 return $metadata->{values}{all_from} || ''; 186} 187 188'Readme!'; 189 190__END__ 191 192=head1 NAME 193 194Module::Install::ReadmeFromPod - A Module::Install extension to automatically convert POD to a README 195 196=head1 SYNOPSIS 197 198 # In Makefile.PL 199 200 use inc::Module::Install; 201 author 'Vestan Pants'; 202 license 'perl'; 203 readme_from 'lib/Some/Module.pm'; 204 readme_from 'lib/Some/Module.pm', { clean => 1, format => 'htm', output_file => 'SomeModule.html' }; 205 206A C<README> file will be generated from the POD of the indicated module file. 207 208Note that the author will need to make sure 209C<Module::Install::ReadmeFromPod> is installed 210before running the C<Makefile.PL>. (The extension will be bundled 211into the user-side distribution). 212 213=head1 DESCRIPTION 214 215Module::Install::ReadmeFromPod is a L<Module::Install> extension that generates 216a C<README> file automatically from an indicated file containing POD, whenever 217the author runs C<Makefile.PL>. Several output formats are supported: plain-text, 218HTML, PDF or manpage. 219 220=head1 COMMANDS 221 222This plugin adds the following Module::Install command: 223 224=over 225 226=item C<readme_from> 227 228Does nothing on the user-side. On the author-side it will generate a C<README> 229file. 230 231 readme_from 'lib/Some/Module.pm'; 232 233If a second parameter is set to a true value then the C<README> will be removed at C<make distclean>. 234 235 readme_from 'lib/Some/Module.pm', 1; 236 237A third parameter can be used to determine the format of the C<README> file. 238 239 readme_from 'lib/Some/Module.pm', 1, 'htm'; 240 241Valid formats for this third parameter are: 242 243=over 244 245=item txt, text 246 247Produce a plain-text C<README> file using L<Pod::Text>. The 'txt' format is the 248default. 249 250=item htm, html 251 252Produce an HTML C<README.htm> file using L<Pod::Html>. 253 254=item man 255 256Produce a C<README.1> manpage using L<Pod::Man>. 257 258=item md 259 260Produce a C<README.md> file using L<Pod::Markdown>. 261 262=item pdf 263 264Produce a PDF C<README.pdf> file with L<App::pod2pdf> if this module is installed. 265 266=back 267 268A fourth parameter can be used to supply an output filename. 269 270 readme_from 'lib/Some/Module.pm', 0, 'pdf', 'SomeModule.pdf'; 271 272Finally, you can pass additional arguments to the POD formatter that handles the 273requested format. 274 275 my @options = ( 'release' => 1.03, 'section' => 8 ); # options for Pod::Man 276 readme_from 'lib/Some/Module.pm', 1, 'man', undef, @options; 277 278But instead of passing this long list of optional arguments to readme_from, you 279should probably pass these arguments as a named hashref for clarity. 280 281 my @options = ( 'release' => 1.03, 'section' => 8 ); 282 readme_from 'lib/Some/Module.pm', {clean => 1, format => 'man', output_file => undef, options => @options}; 283 284If you use the C<all_from> command, C<readme_from> will default to that value. 285 286 all_from 'lib/Some/Module.pm'; 287 readme_from; # Create README from lib/Some/Module.pm 288 readme_from '','clean'; # Put a empty string before 'clean' 289 290=back 291 292=head1 AUTHOR 293 294Chris C<BinGOs> Williams 295 296=head1 LICENSE 297 298Copyright E<copy> Chris Williams 299 300This module may be used, modified, and distributed under the same terms as Perl itself. Please see the license that came with your Perl distribution for details. 301 302=head1 SEE ALSO 303 304L<Module::Install> 305 306L<Pod::Text> 307 308L<Pod::Html> 309 310L<Pod::Man> 311 312L<Pod::Markdown> 313 314L<App::pod2pdf> 315 316=cut 317 318