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