The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

use strict;
use autodie;
my $AUTHOR = "Abdul al Hazred";
main();
sub main {
my $input;
my $outfile;
my $result;
if (@ARGV) {
die("Too many arguments") if @ARGV > 2;
$input = shift(@ARGV);
if (@ARGV == 1) {
write_result(filter_file($input), shift(@ARGV));
} else {
if (-d $input) {
find({no_chdir => 1,
#wanted => sub { if (/\.pm$/ && -f $_) { push(@files, $_) } }
wanted => sub { if (/\.pm$/ && -f $_) { write_result(filter_file($_), $_) } }
},
$input);
} else {
write_result(filter_file($input), $input);
}
}
} else {
write_result(filter_hndl(\*STDIN));
}
}
sub write_result {
my ($result, $outfile) = @_;
if (defined($outfile)) {
open(my $out_hndl, '>', $outfile);
print $out_hndl (@$result);
close($out_hndl);
} else {
print(@$result);
}
}
sub filter_file {
my $file = shift;
open(my $hndl, '<', $file);
my $result = filter_hndl($hndl);
close($hndl);
return $result;
}
sub filter_hndl {
my $hndl = shift;
my ($line, $version);
my @filtered;
while (defined($line = <$hndl>)) {
push(@filtered, $line);
if ($line =~ /^\s*
(?:use\s+version(?:\s+\d+\.\d+)?\s*;\s*)?
our\s+\$VERSION\s*=\s*
(?:version->declare\()?
['"]
(v?\d+(?:\.\d+)+)
['"]
\)?
\s*;\s*$
/x) {
$version = $1;
last;
}
}
die("No version found") if !defined($version);
#
# We assume that there is a '__END__' line followed by a '=pod'.
#
while (defined($line = <$hndl>)) {
push(@filtered, $line);
last if $line =~ /^\s*__END__\s*$/;
}
die("No __END__ found") if !defined($line);
while (defined($line = <$hndl>)) {
push(@filtered, $line);;
last if $line =~ /^=pod\s*$/;
}
die("No =pod found") if !defined($line);
#
# Now we are in the POD section and do our replacements!
#
while (defined($line = <$hndl>)) {
if ($line =~ /^\S/) {
$line =~ s/#AUTHOR#/$AUTHOR/g;
$line =~ s/#VERSION#/$version/g;
}
push(@filtered, $line);
}
return \@filtered;
}
__END__
=pod
=head1 NAME
pm_simple_filter.pl - Filter for Perl module
=head1 SYNOPSIS
pm_simple_filter.pl [[INFILE] OUTFILE]
pm_simple_filter.pl DIR
=head1 DESCRIPTION
To be autmatically called via C<PM_FILTER> during the build process.
Input must be code of a Perl module. It reads the VERSION (must be present!)
and in the POD section, it replaces C<#VERSION#> with that version and
C<#AUTHOR#> with the name of the author (hard coded in this script). It does
not replace in verbatim lines.
Alternatively, the script can also be called with a single directory name
C<DIR>. In this case, the script searches the C<DIR> tree and replaces all
F<*.pm> files that it finds.
The script reads from C<INFILE> and writes to C<OUTFILE>. If only C<INFILE> is
specified, this file is changed. Without arguments, the script reads from
C<STDIN> and writed to C<STDOUT>.
The script assumes that the POD is located at the bottom of the file, after an
C<__END__> followed by optional empty lines followed by a C<=pod>.
=cut