Integrate perlio:
[p5sagit/p5-mst-13.2.git] / lib / Filter / Simple.pm
CommitLineData
b38acab9 1package Filter::Simple;
2
3use vars qw{ $VERSION };
4
5$VERSION = '0.01';
6
7use Filter::Util::Call;
8use Carp;
9
10sub import {
11 my $caller = caller;
12 my ($class, $filter) = @_;
13 croak "Usage: use Filter::Simple sub {...}" unless ref $filter eq CODE;
14 *{"${caller}::import"} = gen_filter_import($caller, $filter);
15 *{"${caller}::unimport"} = \*filter_unimport;
16}
17
18sub gen_filter_import {
19 my ($class, $filter) = @_;
20 return sub {
21 my ($imported_class, @args) = @_;
22 filter_add(
23 sub {
24 my ($status, $off);
25 my $data = "";
26 while ($status = filter_read()) {
27 if (m/^\s*no\s+$class\s*;\s*$/) {
28 $off=1;
29 last;
30 }
31 $data .= $_;
32 $_ = "";
33 }
34 $_ = $data;
35 $filter->(@args) unless $status < 0;
36 $_ .= "no $class;\n" if $off;
37 return length;
38 }
39 );
40 }
41}
42
43sub filter_unimport {
44 filter_del();
45}
46
471;
48
49__END__
50
51=head1 NAME
52
53Filter::Simple - Simplified source filtering
54
55
56=head1 SYNOPSIS
57
58 # in MyFilter.pm:
59
60 package MyFilter;
61
62 use Filter::Simple sub { ... };
63
64
65 # in user's code:
66
67 use MyFilter;
68
69 # this code is filtered
70
71 no MyFilter;
72
73 # this code is not
74
75
76=head1 DESCRIPTION
77
78=head2 The Problem
79
80Source filtering is an immensely powerful feature of recent versions of Perl.
81It allows one to extend the language itself (e.g. the Switch module), to
82simplify the language (e.g. Language::Pythonesque), or to completely recast the
83language (e.g. Lingua::Romana::Perligata). Effectively, it allows one to use
84the full power of Perl as its own, recursively applied, macro language.
85
86The excellent Filter::Util::Call module (by Paul Marquess) provides a
87usable Perl interface to source filtering, but it is often too powerful
88and not nearly as simple as it could be.
89
90To use the module it is necessary to do the following:
91
92=over 4
93
94=item 1.
95
96Download, build, and install the Filter::Util::Call module.
97
98=item 2.
99
100Set up a module that does a C<use Filter::Util::Call>.
101
102=item 3.
103
104Within that module, create an C<import> subroutine.
105
106=item 4.
107
108Within the C<import> subroutine do a call to C<filter_add>, passing
109it either a subroutine reference.
110
111=item 5.
112
113Within the subroutine reference, call C<filter_read> or C<filter_read_exact>
114to "prime" $_ with source code data from the source file that will
115C<use> your module. Check the status value returned to see if any
116source code was actually read in.
117
118=item 6.
119
120Process the contents of $_ to change the source code in the desired manner.
121
122=item 7.
123
124Return the status value.
125
126=item 8.
127
128If the act of unimporting your module (via a C<no>) should cause source
129code filtering to cease, create an C<unimport> subroutine, and have it call
130C<filter_del>. Make sure that the call to C<filter_read> or
131C<filter_read_exact> in step 5 will not accidentally read past the
132C<no>. Effectively this limits source code filters to line-by-line
133operation, unless the C<import> subroutine does some fancy
134pre-pre-parsing of the source code it's filtering.
135
136=back
137
138For example, here is a minimal source code filter in a module named
139BANG.pm. It simply converts every occurrence of the sequence C<BANG\s+BANG>
140to the sequence C<die 'BANG' if $BANG> in any piece of code following a
141C<use BANG;> statement (until the next C<no BANG;> statement, if any):
142
143 package BANG;
144
145 use Filter::Util::Call ;
146
147 sub import {
148 filter_add( sub {
149 my $caller = caller;
150 my ($status, $no_seen, $data);
151 while ($status = filter_read()) {
152 if (/^\s*no\s+$caller\s*;\s*$/) {
153 $no_seen=1;
154 last;
155 }
156 $data .= $_;
157 $_ = "";
158 }
159 $_ = $data;
160 s/BANG\s+BANG/die 'BANG' if \$BANG/g
161 unless $status < 0;
162 $_ .= "no $class;\n" if $no_seen;
163 return 1;
164 })
165 }
166
167 sub unimport {
168 filter_del();
169 }
170
171 1 ;
172
173Given this level of complexity, it's perhaps not surprising that source
174code filtering is still a mystery to most users.
175
176
177=head2 A Solution
178
179The Filter::Simple module provides a vastly simplified interface to
180Filter::Util::Call; one that is sufficient for most common cases.
181
182Instead of the above process, with Filter::Simple the task of setting up
183a source code filter is reduced to:
184
185=over 4
186
187=item 1.
188
189Set up a module that does a C<use Filter::Simple sub { ... }>.
190
191=item 2.
192
193Within the anonymous subroutine passed to C<use Filter::Simple>, process the
194contents of $_ to change the source code in the desired manner.
195
196=back
197
198In other words, the previous example, would become:
199
200 package BANG;
201
202 use Filter::Simple sub {
203 s/BANG\s+BANG/die 'BANG' if \$BANG/g;
204 };
205
206 1 ;
207
208
209=head2 How it works
210
211The Filter::Simple module exports into the package that C<use>s it (e.g.
212package "BANG" in the above example) two automagically constructed
213subroutines -- C<import> and C<unimport> -- which take care of all the
214nasty details.
215
216In addition, the generated C<import> subroutine passes its own argument
217list to the filtering subroutine, so the BANG.pm filter could easily
218be made parametric:
219
220 package BANG;
221
222 use Filter::Simple sub {
223 my ($die_msg, $var_name) = @_;
224 s/BANG\s+BANG/die '$die_msg' if \${$var_name}/g;
225 };
226
227 # and in some user code:
228
229 use BANG "BOOM", "BAM; # "BANG BANG" becomes: die 'BOOM' if $BAM
230
231
232The specified filtering subroutine is called every time a C<use BANG>
233is encountered, and passed all the source code following that call,
234up to either the next C<no BANG;> call or the end of the source file
235(whichever occurs first). Currently, any C<no BANG;> call must appear
236by itself on a separate line, or it is ignored.
237
238
239=head1 AUTHOR
240
241Damian Conway (damian@conway.org)
242
243=head1 COPYRIGHT
244
245 Copyright (c) 2000, Damian Conway. All Rights Reserved.
246 This module is free software. It may be used, redistributed
247and/or modified under the terms of the Perl Artistic License
248 (see http://www.perl.com/perl/misc/Artistic.html)