|
Packit |
72a6dc |
NAME
|
|
Packit |
72a6dc |
Filter::Simple - Simplified source filtering
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
SYNOPSIS
|
|
Packit |
72a6dc |
# in MyFilter.pm:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
package MyFilter;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER { ... };
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
# or just:
|
|
Packit |
72a6dc |
#
|
|
Packit |
72a6dc |
# use Filter::Simple sub { ... };
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
# in user's code:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use MyFilter;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
# this code is filtered
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
no MyFilter;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
# this code is not
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
DESCRIPTION
|
|
Packit |
72a6dc |
The Problem
|
|
Packit |
72a6dc |
Source filtering is an immensely powerful feature of recent versions of
|
|
Packit |
72a6dc |
Perl. It allows one to extend the language itself (e.g. the Switch
|
|
Packit |
72a6dc |
module), to simplify the language (e.g. Language::Pythonesque), or to
|
|
Packit |
72a6dc |
completely recast the language (e.g. Lingua::Romana::Perligata).
|
|
Packit |
72a6dc |
Effectively, it allows one to use the full power of Perl as its own,
|
|
Packit |
72a6dc |
recursively applied, macro language.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
The excellent Filter::Util::Call module (by Paul Marquess) provides a
|
|
Packit |
72a6dc |
usable Perl interface to source filtering, but it is often too powerful
|
|
Packit |
72a6dc |
and not nearly as simple as it could be.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
To use the module it is necessary to do the following:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
1. Download, build, and install the Filter::Util::Call module. (If you
|
|
Packit |
72a6dc |
have Perl 5.7.1 or later, this is already done for you.)
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
2. Set up a module that does a "use Filter::Util::Call".
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
3. Within that module, create an "import" subroutine.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
4. Within the "import" subroutine do a call to "filter_add", passing it
|
|
Packit |
72a6dc |
either a subroutine reference.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
5. Within the subroutine reference, call "filter_read" or
|
|
Packit |
72a6dc |
"filter_read_exact" to "prime" $_ with source code data from the
|
|
Packit |
72a6dc |
source file that will "use" your module. Check the status value
|
|
Packit |
72a6dc |
returned to see if any source code was actually read in.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
6. Process the contents of $_ to change the source code in the desired
|
|
Packit |
72a6dc |
manner.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
7. Return the status value.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
8. If the act of unimporting your module (via a "no") should cause
|
|
Packit |
72a6dc |
source code filtering to cease, create an "unimport" subroutine, and
|
|
Packit |
72a6dc |
have it call "filter_del". Make sure that the call to "filter_read"
|
|
Packit |
72a6dc |
or "filter_read_exact" in step 5 will not accidentally read past the
|
|
Packit |
72a6dc |
"no". Effectively this limits source code filters to line-by-line
|
|
Packit |
72a6dc |
operation, unless the "import" subroutine does some fancy
|
|
Packit |
72a6dc |
pre-pre-parsing of the source code it's filtering.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
For example, here is a minimal source code filter in a module named
|
|
Packit |
72a6dc |
BANG.pm. It simply converts every occurrence of the sequence
|
|
Packit |
72a6dc |
"BANG\s+BANG" to the sequence "die 'BANG' if $BANG" in any piece of code
|
|
Packit |
72a6dc |
following a "use BANG;" statement (until the next "no BANG;" statement,
|
|
Packit |
72a6dc |
if any):
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
package BANG;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Filter::Util::Call ;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
sub import {
|
|
Packit |
72a6dc |
filter_add( sub {
|
|
Packit |
72a6dc |
my $caller = caller;
|
|
Packit |
72a6dc |
my ($status, $no_seen, $data);
|
|
Packit |
72a6dc |
while ($status = filter_read()) {
|
|
Packit |
72a6dc |
if (/^\s*no\s+$caller\s*;\s*?$/) {
|
|
Packit |
72a6dc |
$no_seen=1;
|
|
Packit |
72a6dc |
last;
|
|
Packit |
72a6dc |
}
|
|
Packit |
72a6dc |
$data .= $_;
|
|
Packit |
72a6dc |
$_ = "";
|
|
Packit |
72a6dc |
}
|
|
Packit |
72a6dc |
$_ = $data;
|
|
Packit |
72a6dc |
s/BANG\s+BANG/die 'BANG' if \$BANG/g
|
|
Packit |
72a6dc |
unless $status < 0;
|
|
Packit |
72a6dc |
$_ .= "no $class;\n" if $no_seen;
|
|
Packit |
72a6dc |
return 1;
|
|
Packit |
72a6dc |
})
|
|
Packit |
72a6dc |
}
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
sub unimport {
|
|
Packit |
72a6dc |
filter_del();
|
|
Packit |
72a6dc |
}
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
1 ;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
This level of sophistication puts filtering out of the reach of many
|
|
Packit |
72a6dc |
programmers.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
A Solution
|
|
Packit |
72a6dc |
The Filter::Simple module provides a simplified interface to
|
|
Packit |
72a6dc |
Filter::Util::Call; one that is sufficient for most common cases.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Instead of the above process, with Filter::Simple the task of setting up
|
|
Packit |
72a6dc |
a source code filter is reduced to:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
1. Download and install the Filter::Simple module. (If you have Perl
|
|
Packit |
72a6dc |
5.7.1 or later, this is already done for you.)
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
2. Set up a module that does a "use Filter::Simple" and then calls
|
|
Packit |
72a6dc |
"FILTER { ... }".
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
3. Within the anonymous subroutine or block that is passed to "FILTER",
|
|
Packit |
72a6dc |
process the contents of $_ to change the source code in the desired
|
|
Packit |
72a6dc |
manner.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
In other words, the previous example, would become:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
package BANG;
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER {
|
|
Packit |
72a6dc |
s/BANG\s+BANG/die 'BANG' if \$BANG/g;
|
|
Packit |
72a6dc |
};
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
1 ;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Note that the source code is passed as a single string, so any regex
|
|
Packit |
72a6dc |
that uses "^" or "$" to detect line boundaries will need the "/m" flag.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Disabling or changing <no> behaviour
|
|
Packit |
72a6dc |
By default, the installed filter only filters up to a line consisting of
|
|
Packit |
72a6dc |
one of the three standard source "terminators":
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
no ModuleName; # optional comment
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
or:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
__END__
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
or:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
__DATA__
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
but this can be altered by passing a second argument to "use
|
|
Packit |
72a6dc |
Filter::Simple" or "FILTER" (just remember: there's *no* comma after the
|
|
Packit |
72a6dc |
initial block when you use "FILTER").
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
That second argument may be either a "qr"'d regular expression (which is
|
|
Packit |
72a6dc |
then used to match the terminator line), or a defined false value (which
|
|
Packit |
72a6dc |
indicates that no terminator line should be looked for), or a reference
|
|
Packit |
72a6dc |
to a hash (in which case the terminator is the value associated with the
|
|
Packit |
72a6dc |
key 'terminator'.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
For example, to cause the previous filter to filter only up to a line of
|
|
Packit |
72a6dc |
the form:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
GNAB esu;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
you would write:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
package BANG;
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER {
|
|
Packit |
72a6dc |
s/BANG\s+BANG/die 'BANG' if \$BANG/g;
|
|
Packit |
72a6dc |
}
|
|
Packit |
72a6dc |
qr/^\s*GNAB\s+esu\s*;\s*?$/;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
or:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER {
|
|
Packit |
72a6dc |
s/BANG\s+BANG/die 'BANG' if \$BANG/g;
|
|
Packit |
72a6dc |
}
|
|
Packit |
72a6dc |
{ terminator => qr/^\s*GNAB\s+esu\s*;\s*?$/ };
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
and to prevent the filter's being turned off in any way:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
package BANG;
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER {
|
|
Packit |
72a6dc |
s/BANG\s+BANG/die 'BANG' if \$BANG/g;
|
|
Packit |
72a6dc |
}
|
|
Packit |
72a6dc |
""; # or: 0
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
or:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER {
|
|
Packit |
72a6dc |
s/BANG\s+BANG/die 'BANG' if \$BANG/g;
|
|
Packit |
72a6dc |
}
|
|
Packit |
72a6dc |
{ terminator => "" };
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Note that, no matter what you set the terminator pattern to, the actual
|
|
Packit |
72a6dc |
terminator itself *must* be contained on a single source line.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
All-in-one interface
|
|
Packit |
72a6dc |
Separating the loading of Filter::Simple:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
from the setting up of the filtering:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER { ... };
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
is useful because it allows other code (typically parser support code or
|
|
Packit |
72a6dc |
caching variables) to be defined before the filter is invoked. However,
|
|
Packit |
72a6dc |
there is often no need for such a separation.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
In those cases, it is easier to just append the filtering subroutine and
|
|
Packit |
72a6dc |
any terminator specification directly to the "use" statement that loads
|
|
Packit |
72a6dc |
Filter::Simple, like so:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Filter::Simple sub {
|
|
Packit |
72a6dc |
s/BANG\s+BANG/die 'BANG' if \$BANG/g;
|
|
Packit |
72a6dc |
};
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
This is exactly the same as:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
BEGIN {
|
|
Packit |
72a6dc |
Filter::Simple::FILTER {
|
|
Packit |
72a6dc |
s/BANG\s+BANG/die 'BANG' if \$BANG/g;
|
|
Packit |
72a6dc |
};
|
|
Packit |
72a6dc |
}
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
except that the "FILTER" subroutine is not exported by Filter::Simple.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Filtering only specific components of source code
|
|
Packit |
72a6dc |
One of the problems with a filter like:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER { s/BANG\s+BANG/die 'BANG' if \$BANG/g };
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
is that it indiscriminately applies the specified transformation to the
|
|
Packit |
72a6dc |
entire text of your source program. So something like:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
warn 'BANG BANG, YOU'RE DEAD';
|
|
Packit |
72a6dc |
BANG BANG;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
will become:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
warn 'die 'BANG' if $BANG, YOU'RE DEAD';
|
|
Packit |
72a6dc |
die 'BANG' if $BANG;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
It is very common when filtering source to only want to apply the filter
|
|
Packit |
72a6dc |
to the non-character-string parts of the code, or alternatively to
|
|
Packit |
72a6dc |
*only* the character strings.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Filter::Simple supports this type of filtering by automatically
|
|
Packit |
72a6dc |
exporting the "FILTER_ONLY" subroutine.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
"FILTER_ONLY" takes a sequence of specifiers that install separate (and
|
|
Packit |
72a6dc |
possibly multiple) filters that act on only parts of the source code.
|
|
Packit |
72a6dc |
For example:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER_ONLY
|
|
Packit |
72a6dc |
code => sub { s/BANG\s+BANG/die 'BANG' if \$BANG/g },
|
|
Packit |
72a6dc |
quotelike => sub { s/BANG\s+BANG/CHITTY CHITTY/g };
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
The "code" subroutine will only be used to filter parts of the source
|
|
Packit |
72a6dc |
code that are not quotelikes, POD, or "__DATA__". The "quotelike"
|
|
Packit |
72a6dc |
subroutine only filters Perl quotelikes (including here documents).
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
The full list of alternatives is:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
"code"
|
|
Packit |
72a6dc |
Filters only those sections of the source code that are not
|
|
Packit |
72a6dc |
quotelikes, POD, or "__DATA__".
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
"code_no_comments"
|
|
Packit |
72a6dc |
Filters only those sections of the source code that are not
|
|
Packit |
72a6dc |
quotelikes, POD, comments, or "__DATA__".
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
"executable"
|
|
Packit |
72a6dc |
Filters only those sections of the source code that are not POD or
|
|
Packit |
72a6dc |
"__DATA__".
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
"executable_no_comments"
|
|
Packit |
72a6dc |
Filters only those sections of the source code that are not POD,
|
|
Packit |
72a6dc |
comments, or "__DATA__".
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
"quotelike"
|
|
Packit |
72a6dc |
Filters only Perl quotelikes (as interpreted by
|
|
Packit |
72a6dc |
&Text::Balanced::extract_quotelike).
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
"string"
|
|
Packit |
72a6dc |
Filters only the string literal parts of a Perl quotelike (i.e. the
|
|
Packit |
72a6dc |
contents of a string literal, either half of a "tr///", the second
|
|
Packit |
72a6dc |
half of an "s///").
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
"regex"
|
|
Packit |
72a6dc |
Filters only the pattern literal parts of a Perl quotelike (i.e. the
|
|
Packit |
72a6dc |
contents of a "qr//" or an "m//", the first half of an "s///").
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
"all"
|
|
Packit |
72a6dc |
Filters everything. Identical in effect to "FILTER".
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Except for "FILTER_ONLY code => sub {...}", each of the component
|
|
Packit |
72a6dc |
filters is called repeatedly, once for each component found in the
|
|
Packit |
72a6dc |
source code.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Note that you can also apply two or more of the same type of filter in a
|
|
Packit |
72a6dc |
single "FILTER_ONLY". For example, here's a simple macro-preprocessor
|
|
Packit |
72a6dc |
that is only applied within regexes, with a final debugging pass that
|
|
Packit |
72a6dc |
prints the resulting source code:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Regexp::Common;
|
|
Packit |
72a6dc |
FILTER_ONLY
|
|
Packit |
72a6dc |
regex => sub { s/!\[/[^/g },
|
|
Packit |
72a6dc |
regex => sub { s/%d/$RE{num}{int}/g },
|
|
Packit |
72a6dc |
regex => sub { s/%f/$RE{num}{real}/g },
|
|
Packit |
72a6dc |
all => sub { print if $::DEBUG };
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Filtering only the code parts of source code
|
|
Packit |
72a6dc |
Most source code ceases to be grammatically correct when it is broken up
|
|
Packit |
72a6dc |
into the pieces between string literals and regexes. So the 'code' and
|
|
Packit |
72a6dc |
'code_no_comments' component filter behave slightly differently from the
|
|
Packit |
72a6dc |
other partial filters described in the previous section.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Rather than calling the specified processor on each individual piece of
|
|
Packit |
72a6dc |
code (i.e. on the bits between quotelikes), the 'code...' partial
|
|
Packit |
72a6dc |
filters operate on the entire source code, but with the quotelike bits
|
|
Packit |
72a6dc |
(and, in the case of 'code_no_comments', the comments) "blanked out".
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
That is, a 'code...' filter *replaces* each quoted string, quotelike,
|
|
Packit |
72a6dc |
regex, POD, and __DATA__ section with a placeholder. The delimiters of
|
|
Packit |
72a6dc |
this placeholder are the contents of the $; variable at the time the
|
|
Packit |
72a6dc |
filter is applied (normally "\034"). The remaining four bytes are a
|
|
Packit |
72a6dc |
unique identifier for the component being replaced.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
This approach makes it comparatively easy to write code preprocessors
|
|
Packit |
72a6dc |
without worrying about the form or contents of strings, regexes, etc.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
For convenience, during a 'code...' filtering operation, Filter::Simple
|
|
Packit |
72a6dc |
provides a package variable ($Filter::Simple::placeholder) that contains
|
|
Packit |
72a6dc |
a pre-compiled regex that matches any placeholder...and captures the
|
|
Packit |
72a6dc |
identifier within the placeholder. Placeholders can be moved and
|
|
Packit |
72a6dc |
re-ordered within the source code as needed.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
In addition, a second package variable (@Filter::Simple::components)
|
|
Packit |
72a6dc |
contains a list of the various pieces of $_, as they were originally
|
|
Packit |
72a6dc |
split up to allow placeholders to be inserted.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Once the filtering has been applied, the original strings, regexes, POD,
|
|
Packit |
72a6dc |
etc. are re-inserted into the code, by replacing each placeholder with
|
|
Packit |
72a6dc |
the corresponding original component (from @components). Note that this
|
|
Packit |
72a6dc |
means that the @components variable must be treated with extreme care
|
|
Packit |
72a6dc |
within the filter. The @components array stores the "back- translations"
|
|
Packit |
72a6dc |
of each placeholder inserted into $_, as well as the interstitial source
|
|
Packit |
72a6dc |
code between placeholders. If the placeholder backtranslations are
|
|
Packit |
72a6dc |
altered in @components, they will be similarly changed when the
|
|
Packit |
72a6dc |
placeholders are removed from $_ after the filter is complete.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
For example, the following filter detects concatenated pairs of
|
|
Packit |
72a6dc |
strings/quotelikes and reverses the order in which they are
|
|
Packit |
72a6dc |
concatenated:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
package DemoRevCat;
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER_ONLY code => sub {
|
|
Packit |
72a6dc |
my $ph = $Filter::Simple::placeholder;
|
|
Packit |
72a6dc |
s{ ($ph) \s* [.] \s* ($ph) }{ $2.$1 }gx
|
|
Packit |
72a6dc |
};
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Thus, the following code:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use DemoRevCat;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
my $str = "abc" . q(def);
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
print "$str\n";
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
would become:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
my $str = q(def)."abc";
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
print "$str\n";
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
and hence print:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
defabc
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Using Filter::Simple with an explicit "import" subroutine
|
|
Packit |
72a6dc |
Filter::Simple generates a special "import" subroutine for your module
|
|
Packit |
72a6dc |
(see "How it works") which would normally replace any "import"
|
|
Packit |
72a6dc |
subroutine you might have explicitly declared.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
However, Filter::Simple is smart enough to notice your existing "import"
|
|
Packit |
72a6dc |
and Do The Right Thing with it. That is, if you explicitly define an
|
|
Packit |
72a6dc |
"import" subroutine in a package that's using Filter::Simple, that
|
|
Packit |
72a6dc |
"import" subroutine will still be invoked immediately after any filter
|
|
Packit |
72a6dc |
you install.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
The only thing you have to remember is that the "import" subroutine
|
|
Packit |
72a6dc |
*must* be declared *before* the filter is installed. If you use "FILTER"
|
|
Packit |
72a6dc |
to install the filter:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
package Filter::TurnItUpTo11;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER { s/(\w+)/\U$1/ };
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
that will almost never be a problem, but if you install a filtering
|
|
Packit |
72a6dc |
subroutine by passing it directly to the "use Filter::Simple" statement:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
package Filter::TurnItUpTo11;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Filter::Simple sub{ s/(\w+)/\U$1/ };
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
then you must make sure that your "import" subroutine appears before
|
|
Packit |
72a6dc |
that "use" statement.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Using Filter::Simple and Exporter together
|
|
Packit |
72a6dc |
Likewise, Filter::Simple is also smart enough to Do The Right Thing if
|
|
Packit |
72a6dc |
you use Exporter:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
package Switch;
|
|
Packit |
72a6dc |
use base Exporter;
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
@EXPORT = qw(switch case);
|
|
Packit |
72a6dc |
@EXPORT_OK = qw(given when);
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER { $_ = magic_Perl_filter($_) }
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Immediately after the filter has been applied to the source,
|
|
Packit |
72a6dc |
Filter::Simple will pass control to Exporter, so it can do its magic
|
|
Packit |
72a6dc |
too.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Of course, here too, Filter::Simple has to know you're using Exporter
|
|
Packit |
72a6dc |
before it applies the filter. That's almost never a problem, but if
|
|
Packit |
72a6dc |
you're nervous about it, you can guarantee that things will work
|
|
Packit |
72a6dc |
correctly by ensuring that your "use base Exporter" always precedes your
|
|
Packit |
72a6dc |
"use Filter::Simple".
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
How it works
|
|
Packit |
72a6dc |
The Filter::Simple module exports into the package that calls "FILTER"
|
|
Packit |
72a6dc |
(or "use"s it directly) -- such as package "BANG" in the above example
|
|
Packit |
72a6dc |
-- two automagically constructed subroutines -- "import" and "unimport"
|
|
Packit |
72a6dc |
-- which take care of all the nasty details.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
In addition, the generated "import" subroutine passes its own argument
|
|
Packit |
72a6dc |
list to the filtering subroutine, so the BANG.pm filter could easily be
|
|
Packit |
72a6dc |
made parametric:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
package BANG;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use Filter::Simple;
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
FILTER {
|
|
Packit |
72a6dc |
my ($die_msg, $var_name) = @_;
|
|
Packit |
72a6dc |
s/BANG\s+BANG/die '$die_msg' if \${$var_name}/g;
|
|
Packit |
72a6dc |
};
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
# and in some user code:
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
use BANG "BOOM", "BAM"; # "BANG BANG" becomes: die 'BOOM' if $BAM
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
The specified filtering subroutine is called every time a "use BANG" is
|
|
Packit |
72a6dc |
encountered, and passed all the source code following that call, up to
|
|
Packit |
72a6dc |
either the next "no BANG;" (or whatever terminator you've set) or the
|
|
Packit |
72a6dc |
end of the source file, whichever occurs first. By default, any "no
|
|
Packit |
72a6dc |
BANG;" call must appear by itself on a separate line, or it is ignored.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
AUTHOR
|
|
Packit |
72a6dc |
Damian Conway
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
CONTACT
|
|
Packit |
72a6dc |
Filter::Simple is now maintained by the Perl5-Porters. Please submit bug
|
|
Packit |
72a6dc |
via the "perlbug" tool that comes with your perl. For usage
|
|
Packit |
72a6dc |
instructions, read "perldoc perlbug" or possibly "man perlbug". For
|
|
Packit |
72a6dc |
mostly anything else, please contact <perl5-porters@perl.org>.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Maintainer of the CPAN release is Steffen Mueller <smueller@cpan.org>.
|
|
Packit |
72a6dc |
Contact him with technical difficulties with respect to the packaging of
|
|
Packit |
72a6dc |
the CPAN module.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
Praise of the module, flowers, and presents still go to the author,
|
|
Packit |
72a6dc |
Damian Conway <damian@conway.org>.
|
|
Packit |
72a6dc |
|
|
Packit |
72a6dc |
COPYRIGHT AND LICENSE
|
|
Packit |
72a6dc |
Copyright (c) 2000-2014, Damian Conway. All Rights Reserved.
|
|
Packit |
72a6dc |
This module is free software. It may be used, redistributed
|
|
Packit |
72a6dc |
and/or modified under the same terms as Perl itself.
|
|
Packit |
72a6dc |
|