home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / share / perl5 / namespace / clean.pm < prev   
Encoding:
Perl POD Document  |  2010-06-14  |  9.9 KB  |  373 lines

  1. package namespace::clean;
  2. BEGIN {
  3.   $namespace::clean::AUTHORITY = 'cpan:PHAYLON';
  4. }
  5. BEGIN {
  6.   $namespace::clean::VERSION = '0.18';
  7. }
  8. # ABSTRACT: Keep imports and functions out of your namespace
  9.  
  10. use warnings;
  11. use strict;
  12.  
  13. use vars qw( $STORAGE_VAR );
  14. use Sub::Name 0.04 qw(subname);
  15. use Sub::Identify 0.04 qw(sub_fullname);
  16. use Package::Stash 0.03;
  17. use B::Hooks::EndOfScope 0.07;
  18.  
  19. $STORAGE_VAR = '__NAMESPACE_CLEAN_STORAGE';
  20.  
  21.  
  22. my $RemoveSubs = sub {
  23.  
  24.     my $cleanee = shift;
  25.     my $store   = shift;
  26.     my $cleanee_stash = Package::Stash->new($cleanee);
  27.     my $deleted_stash = Package::Stash->new("namespace::clean::deleted::$cleanee");
  28.   SYMBOL:
  29.     for my $f (@_) {
  30.         my $variable = "&$f";
  31.         # ignore already removed symbols
  32.         next SYMBOL if $store->{exclude}{ $f };
  33.  
  34.         next SYMBOL unless $cleanee_stash->has_package_symbol($variable);
  35.  
  36.         if (ref(\$cleanee_stash->namespace->{$f}) eq 'GLOB') {
  37.             # convince the Perl debugger to work
  38.             # it assumes that sub_fullname($sub) can always be used to find the CV again
  39.             # since we are deleting the glob where the subroutine was originally
  40.             # defined, that assumption no longer holds, so we need to move it
  41.             # elsewhere and point the CV's name to the new glob.
  42.             my $sub = $cleanee_stash->get_package_symbol($variable);
  43.             if ( sub_fullname($sub) eq ($cleanee_stash->name . "::$f") ) {
  44.                 my $new_fq = $deleted_stash->name . "::$f";
  45.                 subname($new_fq, $sub);
  46.                 $deleted_stash->add_package_symbol($variable, $sub);
  47.             }
  48.         }
  49.  
  50.         $cleanee_stash->remove_package_symbol($variable);
  51.     }
  52. };
  53.  
  54. sub clean_subroutines {
  55.     my ($nc, $cleanee, @subs) = @_;
  56.     $RemoveSubs->($cleanee, {}, @subs);
  57. }
  58.  
  59.  
  60. sub import {
  61.     my ($pragma, @args) = @_;
  62.  
  63.     my (%args, $is_explicit);
  64.  
  65.   ARG:
  66.     while (@args) {
  67.  
  68.         if ($args[0] =~ /^\-/) {
  69.             my $key = shift @args;
  70.             my $value = shift @args;
  71.             $args{ $key } = $value;
  72.         }
  73.         else {
  74.             $is_explicit++;
  75.             last ARG;
  76.         }
  77.     }
  78.  
  79.     my $cleanee = exists $args{ -cleanee } ? $args{ -cleanee } : scalar caller;
  80.     if ($is_explicit) {
  81.         on_scope_end {
  82.             $RemoveSubs->($cleanee, {}, @args);
  83.         };
  84.     }
  85.     else {
  86.  
  87.         # calling class, all current functions and our storage
  88.         my $functions = $pragma->get_functions($cleanee);
  89.         my $store     = $pragma->get_class_store($cleanee);
  90.         my $stash     = Package::Stash->new($cleanee);
  91.  
  92.         # except parameter can be array ref or single value
  93.         my %except = map {( $_ => 1 )} (
  94.             $args{ -except }
  95.             ? ( ref $args{ -except } eq 'ARRAY' ? @{ $args{ -except } } : $args{ -except } )
  96.             : ()
  97.         );
  98.  
  99.         # register symbols for removal, if they have a CODE entry
  100.         for my $f (keys %$functions) {
  101.             next if     $except{ $f };
  102.             next unless $stash->has_package_symbol("&$f");
  103.             $store->{remove}{ $f } = 1;
  104.         }
  105.  
  106.         # register EOF handler on first call to import
  107.         unless ($store->{handler_is_installed}) {
  108.             on_scope_end {
  109.                 $RemoveSubs->($cleanee, $store, keys %{ $store->{remove} });
  110.             };
  111.             $store->{handler_is_installed} = 1;
  112.         }
  113.  
  114.         return 1;
  115.     }
  116. }
  117.  
  118.  
  119. sub unimport {
  120.     my ($pragma, %args) = @_;
  121.  
  122.     # the calling class, the current functions and our storage
  123.     my $cleanee   = exists $args{ -cleanee } ? $args{ -cleanee } : scalar caller;
  124.     my $functions = $pragma->get_functions($cleanee);
  125.     my $store     = $pragma->get_class_store($cleanee);
  126.  
  127.     # register all unknown previous functions as excluded
  128.     for my $f (keys %$functions) {
  129.         next if $store->{remove}{ $f }
  130.              or $store->{exclude}{ $f };
  131.         $store->{exclude}{ $f } = 1;
  132.     }
  133.  
  134.     return 1;
  135. }
  136.  
  137.  
  138. sub get_class_store {
  139.     my ($pragma, $class) = @_;
  140.     my $stash = Package::Stash->new($class);
  141.     my $var = "%$STORAGE_VAR";
  142.     $stash->add_package_symbol($var, {})
  143.         unless $stash->has_package_symbol($var);
  144.     return $stash->get_package_symbol($var);
  145. }
  146.  
  147.  
  148. sub get_functions {
  149.     my ($pragma, $class) = @_;
  150.  
  151.     my $stash = Package::Stash->new($class);
  152.     return {
  153.         map { $_ => $stash->get_package_symbol("&$_") }
  154.             $stash->list_all_package_symbols('CODE')
  155.     };
  156. }
  157.  
  158.  
  159. no warnings;
  160. 'Danger! Laws of Thermodynamics may not apply.'
  161.  
  162. __END__
  163. =pod
  164.  
  165. =encoding utf-8
  166.  
  167. =head1 NAME
  168.  
  169. namespace::clean - Keep imports and functions out of your namespace
  170.  
  171. =head1 SYNOPSIS
  172.  
  173.   package Foo;
  174.   use warnings;
  175.   use strict;
  176.  
  177.   use Carp qw(croak);   # 'croak' will be removed
  178.  
  179.   sub bar { 23 }        # 'bar' will be removed
  180.  
  181.   # remove all previously defined functions
  182.   use namespace::clean;
  183.  
  184.   sub baz { bar() }     # 'baz' still defined, 'bar' still bound
  185.  
  186.   # begin to collection function names from here again
  187.   no namespace::clean;
  188.  
  189.   sub quux { baz() }    # 'quux' will be removed
  190.  
  191.   # remove all functions defined after the 'no' unimport
  192.   use namespace::clean;
  193.  
  194.   # Will print: 'No', 'No', 'Yes' and 'No'
  195.   print +(__PACKAGE__->can('croak') ? 'Yes' : 'No'), "\n";
  196.   print +(__PACKAGE__->can('bar')   ? 'Yes' : 'No'), "\n";
  197.   print +(__PACKAGE__->can('baz')   ? 'Yes' : 'No'), "\n";
  198.   print +(__PACKAGE__->can('quux')  ? 'Yes' : 'No'), "\n";
  199.  
  200.   1;
  201.  
  202. =head1 DESCRIPTION
  203.  
  204. =head2 Keeping packages clean
  205.  
  206. When you define a function, or import one, into a Perl package, it will
  207. naturally also be available as a method. This does not per se cause
  208. problems, but it can complicate subclassing and, for example, plugin
  209. classes that are included via multiple inheritance by loading them as
  210. base classes.
  211.  
  212. The C<namespace::clean> pragma will remove all previously declared or
  213. imported symbols at the end of the current package's compile cycle.
  214. Functions called in the package itself will still be bound by their
  215. name, but they won't show up as methods on your class or instances.
  216.  
  217. By unimporting via C<no> you can tell C<namespace::clean> to start
  218. collecting functions for the next C<use namespace::clean;> specification.
  219.  
  220. You can use the C<-except> flag to tell C<namespace::clean> that you
  221. don't want it to remove a certain function or method. A common use would
  222. be a module exporting an C<import> method along with some functions:
  223.  
  224.   use ModuleExportingImport;
  225.   use namespace::clean -except => [qw( import )];
  226.  
  227. If you just want to C<-except> a single sub, you can pass it directly.
  228. For more than one value you have to use an array reference.
  229.  
  230. =head2 Explicitly removing functions when your scope is compiled
  231.  
  232. It is also possible to explicitly tell C<namespace::clean> what packages
  233. to remove when the surrounding scope has finished compiling. Here is an
  234. example:
  235.  
  236.   package Foo;
  237.   use strict;
  238.  
  239.   # blessed NOT available
  240.  
  241.   sub my_class {
  242.       use Scalar::Util qw( blessed );
  243.       use namespace::clean qw( blessed );
  244.  
  245.       # blessed available
  246.       return blessed shift;
  247.   }
  248.  
  249.   # blessed NOT available
  250.  
  251. =head2 Moose
  252.  
  253. When using C<namespace::clean> together with L<Moose> you want to keep
  254. the installed C<meta> method. So your classes should look like:
  255.  
  256.   package Foo;
  257.   use Moose;
  258.   use namespace::clean -except => 'meta';
  259.   ...
  260.  
  261. Same goes for L<Moose::Role>.
  262.  
  263. =head2 Cleaning other packages
  264.  
  265. You can tell C<namespace::clean> that you want to clean up another package
  266. instead of the one importing. To do this you have to pass in the C<-cleanee>
  267. option like this:
  268.  
  269.   package My::MooseX::namespace::clean;
  270.   use strict;
  271.  
  272.   use namespace::clean (); # no cleanup, just load
  273.  
  274.   sub import {
  275.       namespace::clean->import(
  276.         -cleanee => scalar(caller),
  277.         -except  => 'meta',
  278.       );
  279.   }
  280.  
  281. If you don't care about C<namespace::clean>s discover-and-C<-except> logic, and
  282. just want to remove subroutines, try L</clean_subroutines>.
  283.  
  284. =head1 METHODS
  285.  
  286. =head2 clean_subroutines
  287.  
  288. This exposes the actual subroutine-removal logic.
  289.  
  290.   namespace::clean->clean_subroutines($cleanee, qw( subA subB ));
  291.  
  292. will remove C<subA> and C<subB> from C<$cleanee>. Note that this will remove the
  293. subroutines B<immediately> and not wait for scope end. If you want to have this
  294. effect at a specific time (e.g. C<namespace::clean> acts on scope compile end)
  295. it is your responsibility to make sure it runs at that time.
  296.  
  297. =head2 import
  298.  
  299. Makes a snapshot of the current defined functions and installs a
  300. L<B::Hooks::EndOfScope> hook in the current scope to invoke the cleanups.
  301.  
  302. =head2 unimport
  303.  
  304. This method will be called when you do a
  305.  
  306.   no namespace::clean;
  307.  
  308. It will start a new section of code that defines functions to clean up.
  309.  
  310. =head2 get_class_store
  311.  
  312. This returns a reference to a hash in a passed package containing
  313. information about function names included and excluded from removal.
  314.  
  315. =head2 get_functions
  316.  
  317. Takes a class as argument and returns all currently defined functions
  318. in it as a hash reference with the function name as key and a typeglob
  319. reference to the symbol as value.
  320.  
  321. =head1 IMPLEMENTATION DETAILS
  322.  
  323. This module works through the effect that a
  324.  
  325.   delete $SomePackage::{foo};
  326.  
  327. will remove the C<foo> symbol from C<$SomePackage> for run time lookups
  328. (e.g., method calls) but will leave the entry alive to be called by
  329. already resolved names in the package itself. C<namespace::clean> will
  330. restore and therefor in effect keep all glob slots that aren't C<CODE>.
  331.  
  332. A test file has been added to the perl core to ensure that this behaviour
  333. will be stable in future releases.
  334.  
  335. Just for completeness sake, if you want to remove the symbol completely,
  336. use C<undef> instead.
  337.  
  338. =head1 SEE ALSO
  339.  
  340. L<B::Hooks::EndOfScope>
  341.  
  342. =head1 THANKS
  343.  
  344. Many thanks to Matt S Trout for the inspiration on the whole idea.
  345.  
  346. =head1 AUTHORS
  347.  
  348. =over 4
  349.  
  350. =item *
  351.  
  352. Robert 'phaylon' Sedlacek <rs@474.at>
  353.  
  354. =item *
  355.  
  356. Florian Ragwitz <rafl@debian.org>
  357.  
  358. =item *
  359.  
  360. Jesse Luehrs <doy@tozt.net>
  361.  
  362. =back
  363.  
  364. =head1 COPYRIGHT AND LICENSE
  365.  
  366. This software is copyright (c) 2010 by Robert 'phaylon' Sedlacek.
  367.  
  368. This is free software; you can redistribute it and/or modify it under
  369. the same terms as the Perl 5 programming language system itself.
  370.  
  371. =cut
  372.  
  373.