Filename | /usr/share/perl5/namespace/clean.pm |
Statements | Executed 221 statements in 3.04ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 884µs | 2.27ms | BEGIN@6 | namespace::clean::
1 | 1 | 1 | 876µs | 5.99ms | BEGIN@11 | namespace::clean::
1 | 1 | 1 | 106µs | 234µs | __ANON__[:252] | namespace::clean::
1 | 1 | 1 | 46µs | 226µs | import | namespace::clean::
1 | 1 | 1 | 32µs | 89µs | get_functions | namespace::clean::
1 | 1 | 1 | 17µs | 38µs | get_class_store | namespace::clean::
1 | 1 | 1 | 12µs | 17µs | BEGIN@3 | namespace::clean::
1 | 1 | 1 | 9µs | 23µs | BEGIN@445 | namespace::clean::
1 | 1 | 1 | 8µs | 41µs | BEGIN@146 | namespace::clean::
1 | 1 | 1 | 6µs | 29µs | BEGIN@147 | namespace::clean::
1 | 1 | 1 | 6µs | 15µs | BEGIN@4 | namespace::clean::
1 | 1 | 1 | 6µs | 16µs | BEGIN@149 | namespace::clean::
1 | 1 | 1 | 6µs | 239µs | __ANON__[:316] | namespace::clean::
0 | 0 | 0 | 0s | 0s | __ANON__[:199] | namespace::clean::
0 | 0 | 0 | 0s | 0s | __ANON__[:289] | namespace::clean::
0 | 0 | 0 | 0s | 0s | clean_subroutines | namespace::clean::
0 | 0 | 0 | 0s | 0s | unimport | namespace::clean::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package namespace::clean; | ||||
2 | |||||
3 | 2 | 26µs | 2 | 22µs | # spent 17µs (12+5) within namespace::clean::BEGIN@3 which was called:
# once (12µs+5µs) by Class::Load::BEGIN@19 at line 3 # spent 17µs making 1 call to namespace::clean::BEGIN@3
# spent 5µs making 1 call to warnings::import |
4 | 2 | 20µs | 2 | 25µs | # spent 15µs (6+10) within namespace::clean::BEGIN@4 which was called:
# once (6µs+10µs) by Class::Load::BEGIN@19 at line 4 # spent 15µs making 1 call to namespace::clean::BEGIN@4
# spent 10µs making 1 call to strict::import |
5 | |||||
6 | 2 | 720µs | 1 | 2.27ms | # spent 2.27ms (884µs+1.39) within namespace::clean::BEGIN@6 which was called:
# once (884µs+1.39ms) by Class::Load::BEGIN@19 at line 6 # spent 2.27ms making 1 call to namespace::clean::BEGIN@6 |
7 | |||||
8 | 1 | 400ns | our $VERSION = '0.25'; | ||
9 | 1 | 100ns | our $STORAGE_VAR = '__NAMESPACE_CLEAN_STORAGE'; | ||
10 | |||||
11 | 2 | 788µs | 2 | 6.02ms | # spent 5.99ms (876µs+5.12) within namespace::clean::BEGIN@11 which was called:
# once (876µs+5.12ms) by Class::Load::BEGIN@19 at line 11 # spent 5.99ms making 1 call to namespace::clean::BEGIN@11
# spent 28µs making 1 call to Sub::Exporter::Progressive::__ANON__[Sub/Exporter/Progressive.pm:40] |
12 | |||||
13 | =head1 NAME | ||||
14 | |||||
15 | namespace::clean - Keep imports and functions out of your namespace | ||||
16 | |||||
17 | =head1 SYNOPSIS | ||||
18 | |||||
19 | package Foo; | ||||
20 | use warnings; | ||||
21 | use strict; | ||||
22 | |||||
23 | use Carp qw(croak); # 'croak' will be removed | ||||
24 | |||||
25 | sub bar { 23 } # 'bar' will be removed | ||||
26 | |||||
27 | # remove all previously defined functions | ||||
28 | use namespace::clean; | ||||
29 | |||||
30 | sub baz { bar() } # 'baz' still defined, 'bar' still bound | ||||
31 | |||||
32 | # begin to collection function names from here again | ||||
33 | no namespace::clean; | ||||
34 | |||||
35 | sub quux { baz() } # 'quux' will be removed | ||||
36 | |||||
37 | # remove all functions defined after the 'no' unimport | ||||
38 | use namespace::clean; | ||||
39 | |||||
40 | # Will print: 'No', 'No', 'Yes' and 'No' | ||||
41 | print +(__PACKAGE__->can('croak') ? 'Yes' : 'No'), "\n"; | ||||
42 | print +(__PACKAGE__->can('bar') ? 'Yes' : 'No'), "\n"; | ||||
43 | print +(__PACKAGE__->can('baz') ? 'Yes' : 'No'), "\n"; | ||||
44 | print +(__PACKAGE__->can('quux') ? 'Yes' : 'No'), "\n"; | ||||
45 | |||||
46 | 1; | ||||
47 | |||||
48 | =head1 DESCRIPTION | ||||
49 | |||||
50 | =head2 Keeping packages clean | ||||
51 | |||||
52 | When you define a function, or import one, into a Perl package, it will | ||||
53 | naturally also be available as a method. This does not per se cause | ||||
54 | problems, but it can complicate subclassing and, for example, plugin | ||||
55 | classes that are included via multiple inheritance by loading them as | ||||
56 | base classes. | ||||
57 | |||||
58 | The C<namespace::clean> pragma will remove all previously declared or | ||||
59 | imported symbols at the end of the current package's compile cycle. | ||||
60 | Functions called in the package itself will still be bound by their | ||||
61 | name, but they won't show up as methods on your class or instances. | ||||
62 | |||||
63 | By unimporting via C<no> you can tell C<namespace::clean> to start | ||||
64 | collecting functions for the next C<use namespace::clean;> specification. | ||||
65 | |||||
66 | You can use the C<-except> flag to tell C<namespace::clean> that you | ||||
67 | don't want it to remove a certain function or method. A common use would | ||||
68 | be a module exporting an C<import> method along with some functions: | ||||
69 | |||||
70 | use ModuleExportingImport; | ||||
71 | use namespace::clean -except => [qw( import )]; | ||||
72 | |||||
73 | If you just want to C<-except> a single sub, you can pass it directly. | ||||
74 | For more than one value you have to use an array reference. | ||||
75 | |||||
76 | =head2 Explicitly removing functions when your scope is compiled | ||||
77 | |||||
78 | It is also possible to explicitly tell C<namespace::clean> what packages | ||||
79 | to remove when the surrounding scope has finished compiling. Here is an | ||||
80 | example: | ||||
81 | |||||
82 | package Foo; | ||||
83 | use strict; | ||||
84 | |||||
85 | # blessed NOT available | ||||
86 | |||||
87 | sub my_class { | ||||
88 | use Scalar::Util qw( blessed ); | ||||
89 | use namespace::clean qw( blessed ); | ||||
90 | |||||
91 | # blessed available | ||||
92 | return blessed shift; | ||||
93 | } | ||||
94 | |||||
95 | # blessed NOT available | ||||
96 | |||||
97 | =head2 Moose | ||||
98 | |||||
99 | When using C<namespace::clean> together with L<Moose> you want to keep | ||||
100 | the installed C<meta> method. So your classes should look like: | ||||
101 | |||||
102 | package Foo; | ||||
103 | use Moose; | ||||
104 | use namespace::clean -except => 'meta'; | ||||
105 | ... | ||||
106 | |||||
107 | Same goes for L<Moose::Role>. | ||||
108 | |||||
109 | =head2 Cleaning other packages | ||||
110 | |||||
111 | You can tell C<namespace::clean> that you want to clean up another package | ||||
112 | instead of the one importing. To do this you have to pass in the C<-cleanee> | ||||
113 | option like this: | ||||
114 | |||||
115 | package My::MooseX::namespace::clean; | ||||
116 | use strict; | ||||
117 | |||||
118 | use namespace::clean (); # no cleanup, just load | ||||
119 | |||||
120 | sub import { | ||||
121 | namespace::clean->import( | ||||
122 | -cleanee => scalar(caller), | ||||
123 | -except => 'meta', | ||||
124 | ); | ||||
125 | } | ||||
126 | |||||
127 | If you don't care about C<namespace::clean>s discover-and-C<-except> logic, and | ||||
128 | just want to remove subroutines, try L</clean_subroutines>. | ||||
129 | |||||
130 | =head1 METHODS | ||||
131 | |||||
132 | =head2 clean_subroutines | ||||
133 | |||||
134 | This exposes the actual subroutine-removal logic. | ||||
135 | |||||
136 | namespace::clean->clean_subroutines($cleanee, qw( subA subB )); | ||||
137 | |||||
138 | will remove C<subA> and C<subB> from C<$cleanee>. Note that this will remove the | ||||
139 | subroutines B<immediately> and not wait for scope end. If you want to have this | ||||
140 | effect at a specific time (e.g. C<namespace::clean> acts on scope compile end) | ||||
141 | it is your responsibility to make sure it runs at that time. | ||||
142 | |||||
143 | =cut | ||||
144 | |||||
145 | # Constant to optimise away the unused code branches | ||||
146 | 2 | 33µs | 2 | 74µs | # spent 41µs (8+33) within namespace::clean::BEGIN@146 which was called:
# once (8µs+33µs) by Class::Load::BEGIN@19 at line 146 # spent 41µs making 1 call to namespace::clean::BEGIN@146
# spent 33µs making 1 call to constant::import |
147 | 2 | 25µs | 2 | 51µs | # spent 29µs (6+23) within namespace::clean::BEGIN@147 which was called:
# once (6µs+23µs) by Class::Load::BEGIN@19 at line 147 # spent 29µs making 1 call to namespace::clean::BEGIN@147
# spent 23µs making 1 call to constant::import |
148 | { | ||||
149 | 3 | 945µs | 2 | 26µs | # spent 16µs (6+10) within namespace::clean::BEGIN@149 which was called:
# once (6µs+10µs) by Class::Load::BEGIN@19 at line 149 # spent 16µs making 1 call to namespace::clean::BEGIN@149
# spent 10µs making 1 call to strict::unimport |
150 | 1 | 2µs | delete ${__PACKAGE__."::"}{FIXUP_NEEDED}; | ||
151 | 1 | 700ns | delete ${__PACKAGE__."::"}{FIXUP_RENAME_SUB}; | ||
152 | } | ||||
153 | |||||
154 | # Debugger fixup necessary before perl 5.15.5 | ||||
155 | # | ||||
156 | # In perl 5.8.9-5.12, it assumes that sub_fullname($sub) can | ||||
157 | # always be used to find the CV again. | ||||
158 | # In perl 5.8.8 and 5.14, it assumes that the name of the glob | ||||
159 | # passed to entersub can be used to find the CV. | ||||
160 | # since we are deleting the glob where the subroutine was originally | ||||
161 | # defined, those assumptions no longer hold. | ||||
162 | # | ||||
163 | # So in 5.8.9-5.12 we need to move it elsewhere and point the | ||||
164 | # CV's name to the new glob. | ||||
165 | # | ||||
166 | # In 5.8.8 and 5.14 we move it elsewhere and rename the | ||||
167 | # original glob by assigning the new glob back to it. | ||||
168 | 1 | 200ns | my $sub_utils_loaded; | ||
169 | my $DebuggerFixup = sub { | ||||
170 | my ($f, $sub, $cleanee_stash, $deleted_stash) = @_; | ||||
171 | |||||
172 | if (FIXUP_RENAME_SUB) { | ||||
173 | if (! defined $sub_utils_loaded ) { | ||||
174 | $sub_utils_loaded = do { | ||||
175 | |||||
176 | # when changing version also change in Makefile.PL | ||||
177 | my $sn_ver = 0.04; | ||||
178 | eval { require Sub::Name; Sub::Name->VERSION($sn_ver) } | ||||
179 | or die "Sub::Name $sn_ver required when running under -d or equivalent: $@"; | ||||
180 | |||||
181 | # when changing version also change in Makefile.PL | ||||
182 | my $si_ver = 0.04; | ||||
183 | eval { require Sub::Identify; Sub::Identify->VERSION($si_ver) } | ||||
184 | or die "Sub::Identify $si_ver required when running under -d or equivalent: $@"; | ||||
185 | |||||
186 | 1; | ||||
187 | } ? 1 : 0; | ||||
188 | } | ||||
189 | |||||
190 | if ( Sub::Identify::sub_fullname($sub) eq ($cleanee_stash->name . "::$f") ) { | ||||
191 | my $new_fq = $deleted_stash->name . "::$f"; | ||||
192 | Sub::Name::subname($new_fq, $sub); | ||||
193 | $deleted_stash->add_symbol("&$f", $sub); | ||||
194 | } | ||||
195 | } | ||||
196 | else { | ||||
197 | $deleted_stash->add_symbol("&$f", $sub); | ||||
198 | } | ||||
199 | 1 | 3µs | }; | ||
200 | |||||
201 | # spent 234µs (106+128) within namespace::clean::__ANON__[/usr/share/perl5/namespace/clean.pm:252] which was called:
# once (106µs+128µs) by namespace::clean::__ANON__[/usr/share/perl5/namespace/clean.pm:316] at line 315 | ||||
202 | 1 | 500ns | my $cleanee = shift; | ||
203 | 1 | 100ns | my $store = shift; | ||
204 | 1 | 10µs | 1 | 5µs | my $cleanee_stash = Package::Stash->new($cleanee); # spent 5µs making 1 call to Package::Stash::XS::new |
205 | 1 | 100ns | my $deleted_stash; | ||
206 | |||||
207 | SYMBOL: | ||||
208 | 1 | 4µs | for my $f (@_) { | ||
209 | |||||
210 | # ignore already removed symbols | ||||
211 | 8 | 2µs | next SYMBOL if $store->{exclude}{ $f }; | ||
212 | |||||
213 | 8 | 42µs | 17 | 35µs | my $sub = $cleanee_stash->get_symbol("&$f") # spent 29µs making 8 calls to Package::Stash::XS::get_symbol, avg 4µs/call
# spent 6µs making 8 calls to Package::Stash::XS::namespace, avg 788ns/call
# spent 500ns making 1 call to Package::Stash::XS::name |
214 | or next SYMBOL; | ||||
215 | |||||
216 | 8 | 1µs | my $need_debugger_fixup = | ||
217 | FIXUP_NEEDED | ||||
218 | && | ||||
219 | $^P | ||||
220 | && | ||||
221 | ref(my $globref = \$cleanee_stash->namespace->{$f}) eq 'GLOB' | ||||
222 | ; | ||||
223 | |||||
224 | if (FIXUP_NEEDED && $need_debugger_fixup) { | ||||
225 | # convince the Perl debugger to work | ||||
226 | # see the comment on top of $DebuggerFixup | ||||
227 | $DebuggerFixup->( | ||||
228 | $f, | ||||
229 | $sub, | ||||
230 | $cleanee_stash, | ||||
231 | $deleted_stash ||= Package::Stash->new("namespace::clean::deleted::$cleanee"), | ||||
232 | ); | ||||
233 | } | ||||
234 | |||||
235 | 32 | 9µs | my @symbols = map { | ||
236 | 8 | 9µs | my $name = $_ . $f; | ||
237 | 32 | 110µs | 64 | 83µs | my $def = $cleanee_stash->get_symbol($name); # spent 74µs making 32 calls to Package::Stash::XS::get_symbol, avg 2µs/call
# spent 10µs making 32 calls to Package::Stash::XS::namespace, avg 297ns/call |
238 | 32 | 7µs | defined($def) ? [$name, $def] : () | ||
239 | } '$', '@', '%', ''; | ||||
240 | |||||
241 | 8 | 31µs | 16 | 22µs | $cleanee_stash->remove_glob($f); # spent 20µs making 8 calls to Package::Stash::XS::remove_glob, avg 3µs/call
# spent 2µs making 8 calls to Package::Stash::XS::namespace, avg 288ns/call |
242 | |||||
243 | # if this perl needs no renaming trick we need to | ||||
244 | # rename the original glob after the fact | ||||
245 | # (see commend of $DebuggerFixup | ||||
246 | if (FIXUP_NEEDED && !FIXUP_RENAME_SUB && $need_debugger_fixup) { | ||||
247 | *$globref = $deleted_stash->namespace->{$f}; | ||||
248 | } | ||||
249 | |||||
250 | 8 | 9µs | $cleanee_stash->add_symbol(@$_) for @symbols; | ||
251 | } | ||||
252 | 1 | 1µs | }; | ||
253 | |||||
254 | sub clean_subroutines { | ||||
255 | my ($nc, $cleanee, @subs) = @_; | ||||
256 | $RemoveSubs->($cleanee, {}, @subs); | ||||
257 | } | ||||
258 | |||||
259 | =head2 import | ||||
260 | |||||
261 | Makes a snapshot of the current defined functions and installs a | ||||
262 | L<B::Hooks::EndOfScope> hook in the current scope to invoke the cleanups. | ||||
263 | |||||
264 | =cut | ||||
265 | |||||
266 | # spent 226µs (46+180) within namespace::clean::import which was called:
# once (46µs+180µs) by Class::Load::BEGIN@19 at line 19 of Class/Load.pm | ||||
267 | 1 | 600ns | my ($pragma, @args) = @_; | ||
268 | |||||
269 | 1 | 0s | my (%args, $is_explicit); | ||
270 | |||||
271 | ARG: | ||||
272 | 1 | 400ns | while (@args) { | ||
273 | |||||
274 | if ($args[0] =~ /^\-/) { | ||||
275 | my $key = shift @args; | ||||
276 | my $value = shift @args; | ||||
277 | $args{ $key } = $value; | ||||
278 | } | ||||
279 | else { | ||||
280 | $is_explicit++; | ||||
281 | last ARG; | ||||
282 | } | ||||
283 | } | ||||
284 | |||||
285 | 1 | 1µs | my $cleanee = exists $args{ -cleanee } ? $args{ -cleanee } : scalar caller; | ||
286 | 1 | 200ns | if ($is_explicit) { | ||
287 | on_scope_end { | ||||
288 | $RemoveSubs->($cleanee, {}, @args); | ||||
289 | }; | ||||
290 | } | ||||
291 | else { | ||||
292 | |||||
293 | # calling class, all current functions and our storage | ||||
294 | 1 | 2µs | 1 | 89µs | my $functions = $pragma->get_functions($cleanee); # spent 89µs making 1 call to namespace::clean::get_functions |
295 | 1 | 2µs | 1 | 38µs | my $store = $pragma->get_class_store($cleanee); # spent 38µs making 1 call to namespace::clean::get_class_store |
296 | 1 | 5µs | 1 | 3µs | my $stash = Package::Stash->new($cleanee); # spent 3µs making 1 call to Package::Stash::XS::new |
297 | |||||
298 | # except parameter can be array ref or single value | ||||
299 | my %except = map {( $_ => 1 )} ( | ||||
300 | $args{ -except } | ||||
301 | ? ( ref $args{ -except } eq 'ARRAY' ? @{ $args{ -except } } : $args{ -except } ) | ||||
302 | 1 | 1µs | : () | ||
303 | ); | ||||
304 | |||||
305 | # register symbols for removal, if they have a CODE entry | ||||
306 | 1 | 2µs | for my $f (keys %$functions) { | ||
307 | 8 | 800ns | next if $except{ $f }; | ||
308 | 8 | 39µs | 17 | 34µs | next unless $stash->has_symbol("&$f"); # spent 28µs making 8 calls to Package::Stash::XS::has_symbol, avg 3µs/call
# spent 6µs making 8 calls to Package::Stash::XS::namespace, avg 775ns/call
# spent 500ns making 1 call to Package::Stash::XS::name |
309 | 8 | 6µs | $store->{remove}{ $f } = 1; | ||
310 | } | ||||
311 | |||||
312 | # register EOF handler on first call to import | ||||
313 | 1 | 1µs | unless ($store->{handler_is_installed}) { | ||
314 | # spent 239µs (6+234) within namespace::clean::__ANON__[/usr/share/perl5/namespace/clean.pm:316] which was called:
# once (6µs+234µs) by B::Hooks::EndOfScope::XS::__ANON__[/usr/share/perl5/B/Hooks/EndOfScope/XS.pm:26] at line 26 of B/Hooks/EndOfScope/XS.pm | ||||
315 | 1 | 5µs | 1 | 234µs | $RemoveSubs->($cleanee, $store, keys %{ $store->{remove} }); # spent 234µs making 1 call to namespace::clean::__ANON__[namespace/clean.pm:252] |
316 | 1 | 3µs | 1 | 24µs | }; # spent 24µs making 1 call to B::Hooks::EndOfScope::XS::on_scope_end |
317 | 1 | 500ns | $store->{handler_is_installed} = 1; | ||
318 | } | ||||
319 | |||||
320 | 1 | 10µs | return 1; | ||
321 | } | ||||
322 | } | ||||
323 | |||||
324 | =head2 unimport | ||||
325 | |||||
326 | This method will be called when you do a | ||||
327 | |||||
328 | no namespace::clean; | ||||
329 | |||||
330 | It will start a new section of code that defines functions to clean up. | ||||
331 | |||||
332 | =cut | ||||
333 | |||||
334 | sub unimport { | ||||
335 | my ($pragma, %args) = @_; | ||||
336 | |||||
337 | # the calling class, the current functions and our storage | ||||
338 | my $cleanee = exists $args{ -cleanee } ? $args{ -cleanee } : scalar caller; | ||||
339 | my $functions = $pragma->get_functions($cleanee); | ||||
340 | my $store = $pragma->get_class_store($cleanee); | ||||
341 | |||||
342 | # register all unknown previous functions as excluded | ||||
343 | for my $f (keys %$functions) { | ||||
344 | next if $store->{remove}{ $f } | ||||
345 | or $store->{exclude}{ $f }; | ||||
346 | $store->{exclude}{ $f } = 1; | ||||
347 | } | ||||
348 | |||||
349 | return 1; | ||||
350 | } | ||||
351 | |||||
352 | =head2 get_class_store | ||||
353 | |||||
354 | This returns a reference to a hash in a passed package containing | ||||
355 | information about function names included and excluded from removal. | ||||
356 | |||||
357 | =cut | ||||
358 | |||||
359 | # spent 38µs (17+21) within namespace::clean::get_class_store which was called:
# once (17µs+21µs) by namespace::clean::import at line 295 | ||||
360 | 1 | 500ns | my ($pragma, $class) = @_; | ||
361 | 1 | 6µs | 1 | 3µs | my $stash = Package::Stash->new($class); # spent 3µs making 1 call to Package::Stash::XS::new |
362 | 1 | 500ns | my $var = "%$STORAGE_VAR"; | ||
363 | 1 | 24µs | 5 | 18µs | $stash->add_symbol($var, {}) # spent 7µs making 1 call to Package::Stash::XS::has_symbol
# spent 6µs making 1 call to Package::Stash::XS::add_symbol
# spent 4µs making 2 calls to Package::Stash::XS::namespace, avg 2µs/call
# spent 400ns making 1 call to Package::Stash::XS::name |
364 | unless $stash->has_symbol($var); | ||||
365 | 1 | 9µs | 2 | 4µs | return $stash->get_symbol($var); # spent 4µs making 1 call to Package::Stash::XS::get_symbol
# spent 300ns making 1 call to Package::Stash::XS::namespace |
366 | } | ||||
367 | |||||
368 | =head2 get_functions | ||||
369 | |||||
370 | Takes a class as argument and returns all currently defined functions | ||||
371 | in it as a hash reference with the function name as key and a typeglob | ||||
372 | reference to the symbol as value. | ||||
373 | |||||
374 | =cut | ||||
375 | |||||
376 | # spent 89µs (32+57) within namespace::clean::get_functions which was called:
# once (32µs+57µs) by namespace::clean::import at line 294 | ||||
377 | 1 | 300ns | my ($pragma, $class) = @_; | ||
378 | |||||
379 | 1 | 18µs | 1 | 12µs | my $stash = Package::Stash->new($class); # spent 12µs making 1 call to Package::Stash::XS::new |
380 | return { | ||||
381 | 1 | 73µs | 19 | 58µs | map { $_ => $stash->get_symbol("&$_") } # spent 26µs making 8 calls to Package::Stash::XS::get_symbol, avg 3µs/call
# spent 19µs making 1 call to Package::Stash::XS::list_all_symbols
# spent 13µs making 9 calls to Package::Stash::XS::namespace, avg 1µs/call
# spent 700ns making 1 call to Package::Stash::XS::name |
382 | $stash->list_all_symbols('CODE') | ||||
383 | }; | ||||
384 | } | ||||
385 | |||||
386 | =head1 IMPLEMENTATION DETAILS | ||||
387 | |||||
388 | This module works through the effect that a | ||||
389 | |||||
390 | delete $SomePackage::{foo}; | ||||
391 | |||||
392 | will remove the C<foo> symbol from C<$SomePackage> for run time lookups | ||||
393 | (e.g., method calls) but will leave the entry alive to be called by | ||||
394 | already resolved names in the package itself. C<namespace::clean> will | ||||
395 | restore and therefor in effect keep all glob slots that aren't C<CODE>. | ||||
396 | |||||
397 | A test file has been added to the perl core to ensure that this behaviour | ||||
398 | will be stable in future releases. | ||||
399 | |||||
400 | Just for completeness sake, if you want to remove the symbol completely, | ||||
401 | use C<undef> instead. | ||||
402 | |||||
403 | =head1 SEE ALSO | ||||
404 | |||||
405 | L<B::Hooks::EndOfScope> | ||||
406 | |||||
407 | =head1 THANKS | ||||
408 | |||||
409 | Many thanks to Matt S Trout for the inspiration on the whole idea. | ||||
410 | |||||
411 | =head1 AUTHORS | ||||
412 | |||||
413 | =over | ||||
414 | |||||
415 | =item * | ||||
416 | |||||
417 | Robert 'phaylon' Sedlacek <rs@474.at> | ||||
418 | |||||
419 | =item * | ||||
420 | |||||
421 | Florian Ragwitz <rafl@debian.org> | ||||
422 | |||||
423 | =item * | ||||
424 | |||||
425 | Jesse Luehrs <doy@tozt.net> | ||||
426 | |||||
427 | =item * | ||||
428 | |||||
429 | Peter Rabbitson <ribasushi@cpan.org> | ||||
430 | |||||
431 | =item * | ||||
432 | |||||
433 | Father Chrysostomos <sprout@cpan.org> | ||||
434 | |||||
435 | =back | ||||
436 | |||||
437 | =head1 COPYRIGHT AND LICENSE | ||||
438 | |||||
439 | This software is copyright (c) 2011 by L</AUTHORS> | ||||
440 | |||||
441 | This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. | ||||
442 | |||||
443 | =cut | ||||
444 | |||||
445 | 2 | 30µs | 2 | 38µs | # spent 23µs (9+14) within namespace::clean::BEGIN@445 which was called:
# once (9µs+14µs) by Class::Load::BEGIN@19 at line 445 # spent 23µs making 1 call to namespace::clean::BEGIN@445
# spent 14µs making 1 call to warnings::unimport |
446 | 1 | 4µs | 'Danger! Laws of Thermodynamics may not apply.' |