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. |
3b131e01 |
96 | (If you are using Perl 5.7.1 or later, you already have Filter::Util::Call.) |
b38acab9 |
97 | |
98 | =item 2. |
99 | |
100 | Set up a module that does a C<use Filter::Util::Call>. |
101 | |
102 | =item 3. |
103 | |
104 | Within that module, create an C<import> subroutine. |
105 | |
106 | =item 4. |
107 | |
108 | Within the C<import> subroutine do a call to C<filter_add>, passing |
109 | it either a subroutine reference. |
110 | |
111 | =item 5. |
112 | |
113 | Within the subroutine reference, call C<filter_read> or C<filter_read_exact> |
114 | to "prime" $_ with source code data from the source file that will |
115 | C<use> your module. Check the status value returned to see if any |
116 | source code was actually read in. |
117 | |
118 | =item 6. |
119 | |
120 | Process the contents of $_ to change the source code in the desired manner. |
121 | |
122 | =item 7. |
123 | |
124 | Return the status value. |
125 | |
126 | =item 8. |
127 | |
128 | If the act of unimporting your module (via a C<no>) should cause source |
129 | code filtering to cease, create an C<unimport> subroutine, and have it call |
130 | C<filter_del>. Make sure that the call to C<filter_read> or |
131 | C<filter_read_exact> in step 5 will not accidentally read past the |
132 | C<no>. Effectively this limits source code filters to line-by-line |
133 | operation, unless the C<import> subroutine does some fancy |
134 | pre-pre-parsing of the source code it's filtering. |
135 | |
136 | =back |
137 | |
138 | For example, here is a minimal source code filter in a module named |
139 | BANG.pm. It simply converts every occurrence of the sequence C<BANG\s+BANG> |
140 | to the sequence C<die 'BANG' if $BANG> in any piece of code following a |
141 | C<use BANG;> statement (until the next C<no BANG;> statement, if any): |
142 | |
143 | package BANG; |
bbc7dcd2 |
144 | |
b38acab9 |
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 | |
7bf0340c |
173 | This level of sophistication puts filtering out of the reach of |
174 | many programmers. |
b38acab9 |
175 | |
176 | |
177 | =head2 A Solution |
178 | |
7bf0340c |
179 | The Filter::Simple module provides a simplified interface to |
b38acab9 |
180 | Filter::Util::Call; one that is sufficient for most common cases. |
181 | |
182 | Instead of the above process, with Filter::Simple the task of setting up |
183 | a source code filter is reduced to: |
184 | |
185 | =over 4 |
186 | |
187 | =item 1. |
188 | |
189 | Set up a module that does a C<use Filter::Simple sub { ... }>. |
190 | |
191 | =item 2. |
192 | |
193 | Within the anonymous subroutine passed to C<use Filter::Simple>, process the |
194 | contents of $_ to change the source code in the desired manner. |
195 | |
196 | =back |
197 | |
198 | In other words, the previous example, would become: |
199 | |
200 | package BANG; |
bbc7dcd2 |
201 | |
b38acab9 |
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 | |
211 | The Filter::Simple module exports into the package that C<use>s it (e.g. |
212 | package "BANG" in the above example) two automagically constructed |
213 | subroutines -- C<import> and C<unimport> -- which take care of all the |
214 | nasty details. |
215 | |
216 | In addition, the generated C<import> subroutine passes its own argument |
217 | list to the filtering subroutine, so the BANG.pm filter could easily |
218 | be made parametric: |
219 | |
220 | package BANG; |
bbc7dcd2 |
221 | |
b38acab9 |
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 | |
232 | The specified filtering subroutine is called every time a C<use BANG> |
233 | is encountered, and passed all the source code following that call, |
234 | up 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 |
236 | by itself on a separate line, or it is ignored. |
237 | |
238 | |
239 | =head1 AUTHOR |
240 | |
241 | Damian Conway (damian@conway.org) |
242 | |
243 | =head1 COPYRIGHT |
244 | |
245 | Copyright (c) 2000, Damian Conway. All Rights Reserved. |
7a57cd46 |
246 | This module is free software; you can redistribute it and/or |
247 | modify it under the same terms as Perl itself. |