ExtUtils-PerlPP
view release on metacpan or search on metacpan
...
if (!open(FILE, ">file") || !(print FILE $script) ||
!close(FILE)) {
die "Cannot write file: $!";
}
But in essence, what else is this than a Perl preprocessor?
Traditionally you have to write such a Perl preprocessor for yourself
all the time, although I have found that they always do the same, for
example:
- Fix defaults, for example installation paths.
- Including or excluding code sections. It is a matter of taste
whether one likes to see
if ($] < 5.003) {
# Thirty lines of code following here
...
} else {
# A single line of code
...
}
when already using Perl 5.005. I don't.
This module is dedicated to simplify such tasks. In short, you can use
it like this:
Create a new preprocessor
You start with creating an instance of *ExtUtils::PerlPP* by calling the
*new* constructor:
my $ppp = ExtUtils::PerlPP->new(%attr);
The constructor accepts a list of attributes, including the following:
in_fh The input file, any kind of IO object, for example an instance of
IO::File or IO::Scalar. More general: It can be any object that
offers a *getline* method.
A scalar value (to be distinguished from an IO::Scalar
instance!) will be interpreted as a file name that the method
opens for you.
out_fh The output file; another IO object or any other object that offers a
*print* method. A scalar value is accepted as output file name.
config A hash ref of preprocessor variables. In other words
$ppp->{'config'}->{'var'} = 1;
is what `-Dvar=val' is for the C preprocessor. Similarly you can
compare
delete $ppp->{'config'};
with `-Uvar'. See the section on "Macro replacements" below.
Unlike C, variables may be arbitrarily complex, in particular
you can use hash or array refs as values.
Surprisingly you may pass a scalar value again: In that case the
file of the same name evaluated and the result is used as a
configuration hash. In other words
$ppp->{'config'} = "myapp.cfg";
is similar to
$ppp->{'config'} = do "myapp.cfg";
Such config files can easily be created using the *Data::Dumper*
module. the Data::Dumper(3) manpage.
no_config_default
If a variable name is used, but no such attribute is present in
the *config* hash, then by default the variable is looked up in
the `$Config' from the *Config* module. This behaviour is
suppressed, if you set *no_config_default* to a TRUE value. the
Config(3) manpage.
no_makedirs
By default directories are created silently if required. For
example, if you pass a value of `/usr/local/foo/bar' as output
file and only `/usr/local' exists, then the subdirectory `foo'
will be created. The option *no_makedirs* suppresses this
behaviour.
Running the preprocessor
This is done by executing
$ppp->parse();
A Perl exception will be thrown in case of errors, thus the complete use
might look like this:
eval { $ppp->parse(); };
if ($@) { print "An error occurred: $@\n" }
Using the frontend
Most applications won't call the *new* or *parse* methods directly, but
rather do a
use ExtUtils::PerlPP;
ppp('infile', 'outfile', 'configfile');
This is equivalent to
my $parser = ExtUtils::PerlPP->new('in_fh' => 'infile',
'out_fh' => 'outfile',
'config' => 'configfile');
$parser->parse();
In order to be easily used within Makefiles, the ppp frontend can read
from @ARGV. That is, you can use the module like this:
perl -MExtUtils::PerlPP -e ppp <infile> <outfile> <configfile>
from the commandline.
Macro replacements
The primary use of preprocessor variables (aka attributes of `$ppp-
'{'config'}>) is replacing patterns in the stream written to the output
file. With `$c = $ppp-'{'config'}> in mind the typical patterns and
their replacements are:
~~a~~ $c->{'a'}
~~b~~ $c->{'b'}
~~a->b~~ $c->{'a'}->{'b'}
~~a->e~~ $c->{'a'}->{'e'}
~~a->1~~ $c->{'a'}->[1]
~~a->1->b~~ $c->{'a'}->[1]->{'b'}
I hope the idea is obvious. Real world examples might be:
my $config_file = "~~etc_dir~~/configuration";
my $VERSION = "~~version~~";
Preprocessor variables need not be scalar values: If a variable contains
a code ref, then the module will execute
&$var($ppp, $text);
and replace the pattern with the result. `$text' is the pattern being
replaced, for example, if `$ppp-'{'config'}->{'bar'}> has the value
`\&foo', then `~~bar~~' will be replaced with the result of
foo($ppp, "bar");
Arguments are not yet supported.
Creating macros
When talking about code refs, we need a possibility to create them. The
best possibility is creating them within the input file, as in
~&foo&~ my($self, $text) = @_; $text x 2; ~&&~
This example is mainly equivalent to
$ppp->{'config'}->{'foo'} = sub {
my($self, $text) = @_; $text x 2;
};
The `~&var&~' definition must start at the beginning of a line, much
like the C preprocessor. The end pattern ~&&~ may appear at any point,
but the remaining line will be ignored.
Conditional output
The next application of a preprocessor is conditional output, as in an
#ifdef var
...
#endif
segment. This can be done with
~#if#~ <expression>
...
( run in 0.892 second using v1.01-cache-2.11-cpan-39bf76dae61 )