1 package namespace::clean;
2 # ABSTRACT: Keep imports and functions out of your namespace
7 use vars qw( $STORAGE_VAR );
10 our $VERSION = '0.20_01';
12 $STORAGE_VAR = '__NAMESPACE_CLEAN_STORAGE';
16 # when changing also change in Makefile.PL
17 my $b_h_eos_req = '0.07';
20 require B::Hooks::EndOfScope;
21 B::Hooks::EndOfScope->VERSION($b_h_eos_req);
24 B::Hooks::EndOfScope->import('on_scope_end');
27 eval <<'PP' or die $@;
32 package namespace::clean::_TieHintHash;
34 use base 'Tie::ExtraHash';
38 package namespace::clean::_ScopeGuard;
40 sub arm { bless [ $_[1] ] }
42 sub DESTROY { $_[0]->[0]->() }
46 sub on_scope_end (&) {
49 if( my $stack = tied( %^H ) ) {
50 if ( (my $c = ref $stack) ne 'namespace::clean::_TieHintHash') {
52 ========================================================================
53 !!! F A T A L E R R O R !!!
55 foreign tie() of %^H detected
56 ========================================================================
58 namespace::clean is currently operating in pure-perl fallback mode, because
59 your system is lacking the necessary dependency B::Hooks::EndOfScope $b_h_eos_req.
60 In this mode namespace::clean expects to be able to tie() the hinthash %^H,
61 however it is apparently already tied by means unknown to the tie-class
64 Since this is a no-win situation execution will abort here and now. Please
65 try to find out which other module is relying on hinthash tie() ability,
66 and file a bug for both the perpetrator and namespace::clean, so that the
67 authors can figure out an acceptable way of moving forward.
71 push @$stack, namespace::clean::_ScopeGuard->arm(shift);
74 tie( %^H, 'namespace::clean::_TieHintHash', namespace::clean::_ScopeGuard->arm(shift) );
91 use Carp qw(croak); # 'croak' will be removed
93 sub bar { 23 } # 'bar' will be removed
95 # remove all previously defined functions
98 sub baz { bar() } # 'baz' still defined, 'bar' still bound
100 # begin to collection function names from here again
103 sub quux { baz() } # 'quux' will be removed
105 # remove all functions defined after the 'no' unimport
106 use namespace::clean;
108 # Will print: 'No', 'No', 'Yes' and 'No'
109 print +(__PACKAGE__->can('croak') ? 'Yes' : 'No'), "\n";
110 print +(__PACKAGE__->can('bar') ? 'Yes' : 'No'), "\n";
111 print +(__PACKAGE__->can('baz') ? 'Yes' : 'No'), "\n";
112 print +(__PACKAGE__->can('quux') ? 'Yes' : 'No'), "\n";
118 =head2 Keeping packages clean
120 When you define a function, or import one, into a Perl package, it will
121 naturally also be available as a method. This does not per se cause
122 problems, but it can complicate subclassing and, for example, plugin
123 classes that are included via multiple inheritance by loading them as
126 The C<namespace::clean> pragma will remove all previously declared or
127 imported symbols at the end of the current package's compile cycle.
128 Functions called in the package itself will still be bound by their
129 name, but they won't show up as methods on your class or instances.
131 By unimporting via C<no> you can tell C<namespace::clean> to start
132 collecting functions for the next C<use namespace::clean;> specification.
134 You can use the C<-except> flag to tell C<namespace::clean> that you
135 don't want it to remove a certain function or method. A common use would
136 be a module exporting an C<import> method along with some functions:
138 use ModuleExportingImport;
139 use namespace::clean -except => [qw( import )];
141 If you just want to C<-except> a single sub, you can pass it directly.
142 For more than one value you have to use an array reference.
144 =head2 Explicitly removing functions when your scope is compiled
146 It is also possible to explicitly tell C<namespace::clean> what packages
147 to remove when the surrounding scope has finished compiling. Here is an
153 # blessed NOT available
156 use Scalar::Util qw( blessed );
157 use namespace::clean qw( blessed );
160 return blessed shift;
163 # blessed NOT available
167 When using C<namespace::clean> together with L<Moose> you want to keep
168 the installed C<meta> method. So your classes should look like:
172 use namespace::clean -except => 'meta';
175 Same goes for L<Moose::Role>.
177 =head2 Cleaning other packages
179 You can tell C<namespace::clean> that you want to clean up another package
180 instead of the one importing. To do this you have to pass in the C<-cleanee>
183 package My::MooseX::namespace::clean;
186 use namespace::clean (); # no cleanup, just load
189 namespace::clean->import(
190 -cleanee => scalar(caller),
195 If you don't care about C<namespace::clean>s discover-and-C<-except> logic, and
196 just want to remove subroutines, try L</clean_subroutines>.
200 =head2 clean_subroutines
202 This exposes the actual subroutine-removal logic.
204 namespace::clean->clean_subroutines($cleanee, qw( subA subB ));
206 will remove C<subA> and C<subB> from C<$cleanee>. Note that this will remove the
207 subroutines B<immediately> and not wait for scope end. If you want to have this
208 effect at a specific time (e.g. C<namespace::clean> acts on scope compile end)
209 it is your responsibility to make sure it runs at that time.
213 my $sub_utils_loaded;
214 my $DebuggerRename = sub {
215 my ($f, $sub, $cleanee_stash, $deleted_stash) = @_;
217 if (! defined $sub_utils_loaded ) {
218 $sub_utils_loaded = do {
220 eval { require Sub::Name; Sub::Name->VERSION($sn_ver) }
221 or die "Sub::Name $sn_ver required when running under -d or equivalent: $@";
224 eval { require Sub::Identify; Sub::Identify->VERSION($si_ver) }
225 or die "Sub::Identify $si_ver required when running under -d or equivalent: $@";
231 if ( Sub::Identify::sub_fullname($sub) eq ($cleanee_stash->name . "::$f") ) {
232 my $new_fq = $deleted_stash->name . "::$f";
233 Sub::Name::subname($new_fq, $sub);
234 $deleted_stash->add_symbol("&$f", $sub);
238 my $RemoveSubs = sub {
241 my $cleanee_stash = Package::Stash->new($cleanee);
247 # ignore already removed symbols
248 next SYMBOL if $store->{exclude}{ $f };
250 my $sub = $cleanee_stash->get_symbol("&$f")
253 if ($^P and ref(\$cleanee_stash->namespace->{$f}) eq 'GLOB') {
254 # convince the Perl debugger to work
255 # it assumes that sub_fullname($sub) can always be used to find the CV again
256 # since we are deleting the glob where the subroutine was originally
257 # defined, that assumption no longer holds, so we need to move it
258 # elsewhere and point the CV's name to the new glob.
263 $deleted_stash ||= Package::Stash->new("namespace::clean::deleted::$cleanee"),
269 my $def = $cleanee_stash->get_symbol($name);
270 defined($def) ? [$name, $def] : ()
273 $cleanee_stash->remove_glob($f);
275 $cleanee_stash->add_symbol(@$_) for @symbols;
279 sub clean_subroutines {
280 my ($nc, $cleanee, @subs) = @_;
281 $RemoveSubs->($cleanee, {}, @subs);
286 Makes a snapshot of the current defined functions and installs a
287 L<B::Hooks::EndOfScope> hook in the current scope to invoke the cleanups.
292 my ($pragma, @args) = @_;
294 my (%args, $is_explicit);
299 if ($args[0] =~ /^\-/) {
300 my $key = shift @args;
301 my $value = shift @args;
302 $args{ $key } = $value;
310 my $cleanee = exists $args{ -cleanee } ? $args{ -cleanee } : scalar caller;
313 $RemoveSubs->($cleanee, {}, @args);
318 # calling class, all current functions and our storage
319 my $functions = $pragma->get_functions($cleanee);
320 my $store = $pragma->get_class_store($cleanee);
321 my $stash = Package::Stash->new($cleanee);
323 # except parameter can be array ref or single value
324 my %except = map {( $_ => 1 )} (
326 ? ( ref $args{ -except } eq 'ARRAY' ? @{ $args{ -except } } : $args{ -except } )
330 # register symbols for removal, if they have a CODE entry
331 for my $f (keys %$functions) {
332 next if $except{ $f };
333 next unless $stash->has_symbol("&$f");
334 $store->{remove}{ $f } = 1;
337 # register EOF handler on first call to import
338 unless ($store->{handler_is_installed}) {
340 $RemoveSubs->($cleanee, $store, keys %{ $store->{remove} });
342 $store->{handler_is_installed} = 1;
351 This method will be called when you do a
355 It will start a new section of code that defines functions to clean up.
360 my ($pragma, %args) = @_;
362 # the calling class, the current functions and our storage
363 my $cleanee = exists $args{ -cleanee } ? $args{ -cleanee } : scalar caller;
364 my $functions = $pragma->get_functions($cleanee);
365 my $store = $pragma->get_class_store($cleanee);
367 # register all unknown previous functions as excluded
368 for my $f (keys %$functions) {
369 next if $store->{remove}{ $f }
370 or $store->{exclude}{ $f };
371 $store->{exclude}{ $f } = 1;
377 =head2 get_class_store
379 This returns a reference to a hash in a passed package containing
380 information about function names included and excluded from removal.
384 sub get_class_store {
385 my ($pragma, $class) = @_;
386 my $stash = Package::Stash->new($class);
387 my $var = "%$STORAGE_VAR";
388 $stash->add_symbol($var, {})
389 unless $stash->has_symbol($var);
390 return $stash->get_symbol($var);
395 Takes a class as argument and returns all currently defined functions
396 in it as a hash reference with the function name as key and a typeglob
397 reference to the symbol as value.
402 my ($pragma, $class) = @_;
404 my $stash = Package::Stash->new($class);
406 map { $_ => $stash->get_symbol("&$_") }
407 $stash->list_all_symbols('CODE')
411 =head1 IMPLEMENTATION DETAILS
413 This module works through the effect that a
415 delete $SomePackage::{foo};
417 will remove the C<foo> symbol from C<$SomePackage> for run time lookups
418 (e.g., method calls) but will leave the entry alive to be called by
419 already resolved names in the package itself. C<namespace::clean> will
420 restore and therefor in effect keep all glob slots that aren't C<CODE>.
422 A test file has been added to the perl core to ensure that this behaviour
423 will be stable in future releases.
425 Just for completeness sake, if you want to remove the symbol completely,
426 use C<undef> instead.
430 This module is fully functional in a pure-perl environment, where
431 L<B::Hooks::EndOfScope> (with the XS dependency L<Variable::Magic>), may
432 not be available. However in this case this module falls back to a
433 L<tie()|perlfunc/tie> of L<%^H|perlvar/%^H> which may or may not interfere
434 with some crack you may be doing independently of namespace::clean.
436 If you want to ensure that your codebase is protected from this unlikely
437 clash, you need to explicitly depend on L<B::Hooks::EndOfScope>.
441 L<B::Hooks::EndOfScope>
445 Many thanks to Matt S Trout for the inspiration on the whole idea.
453 Robert 'phaylon' Sedlacek <rs@474.at>
457 Florian Ragwitz <rafl@debian.org>
461 Jesse Luehrs <doy@tozt.net>
465 Peter Rabbitson <ribasushi@cpan.org>
469 =head1 COPYRIGHT AND LICENSE
471 This software is copyright (c) 2011 by Robert 'phaylon' Sedlacek.
473 This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
478 'Danger! Laws of Thermodynamics may not apply.'