File Coverage

blib/lib/namespace/autoclean.pm
Criterion Covered Total %
statement 61 76 80.2
branch 28 44 63.6
condition 7 15 46.6
subroutine 13 14 92.8
pod n/a
total 109 149 73.1


line stmt bran cond sub pod time code
1 10     10   1328615 use strict;
  10         17  
  10         379  
2 10     10   50 use warnings;
  10         17  
  10         949  
3              
4             package namespace::autoclean; # git description: 0.30-TRIAL-2-ga0e6aea
5             # ABSTRACT: Keep imports out of your namespace
6             # KEYWORDS: namespaces clean dirty imports exports subroutines methods development
7              
8             our $VERSION = '0.31';
9              
10 10     10   5300 use B::Hooks::EndOfScope 0.12;
  10         139561  
  10         61  
11 10     10   990 use List::Util qw( first );
  10         31  
  10         2732  
12              
13             BEGIN {
14 10 50 33 10   40 if (eval { require Sub::Util } && defined &Sub::Util::subname) {
  10         136  
15 10         344 *subname = \&Sub::Util::subname;
16             }
17             else {
18 0         0 require B;
19             *subname = sub {
20 0         0 my ($coderef) = @_;
21 0 0       0 die 'Not a subroutine reference'
22             unless ref $coderef;
23 0         0 my $cv = B::svref_2object($coderef);
24 0 0       0 die 'Not a subroutine reference'
25             unless $cv->isa('B::CV');
26 0         0 my $gv = $cv->GV;
27             return undef
28 0 0       0 if $gv->isa('B::SPECIAL');
29 0         0 my $stash = $gv->STASH;
30 0 0       0 my $package = $stash->isa('B::SPECIAL') ? '__ANON__' : $stash->NAME;
31 0         0 return $package . '::' . $gv->NAME;
32 0         0 };
33             }
34             }
35              
36 10     10   5105 use namespace::clean 0.20;
  10         55720  
  10         72  
37              
38             #pod =head1 SYNOPSIS
39             #pod
40             #pod package Foo;
41             #pod use namespace::autoclean;
42             #pod use Some::Package qw/imported_function/;
43             #pod
44             #pod sub bar { imported_function('stuff') }
45             #pod
46             #pod # later on:
47             #pod Foo->bar; # works
48             #pod Foo->imported_function; # will fail. imported_function got cleaned after compilation
49             #pod
50             #pod =head1 DESCRIPTION
51             #pod
52             #pod When you import a function into a Perl package, it will naturally also be
53             #pod available as a method.
54             #pod
55             #pod The C<namespace::autoclean> pragma will remove all imported symbols at the end
56             #pod of the current package's compile cycle. Functions called in the package itself
57             #pod will still be bound by their name, but they won't show up as methods on your
58             #pod class or instances.
59             #pod
60             #pod This module is very similar to L<namespace::clean|namespace::clean>, except it
61             #pod will clean all imported functions, no matter if you imported them before or
62             #pod after you C<use>d the pragma. It will also not touch anything that looks like a
63             #pod method.
64             #pod
65             #pod If you're writing an exporter and you want to clean up after yourself (and your
66             #pod peers), you can use the C<-cleanee> switch to specify what package to clean:
67             #pod
68             #pod package My::MooseX::namespace::autoclean;
69             #pod use strict;
70             #pod
71             #pod use namespace::autoclean (); # no cleanup, just load
72             #pod
73             #pod sub import {
74             #pod namespace::autoclean->import(
75             #pod -cleanee => scalar(caller),
76             #pod );
77             #pod }
78             #pod
79             #pod =head1 WHAT IS AND ISN'T CLEANED
80             #pod
81             #pod C<namespace::autoclean> will leave behind anything that it deems a method. For
82             #pod L<Moose> classes, this the based on the C<get_method_list> method
83             #pod on from the L<Class::MOP::Class|metaclass>. For non-Moose classes, anything
84             #pod defined within the package will be identified as a method. This should match
85             #pod Moose's definition of a method. Additionally, the magic subs installed by
86             #pod L<overload> will not be cleaned.
87             #pod
88             #pod =head1 PARAMETERS
89             #pod
90             #pod =head2 -also => [ ITEM | REGEX | SUB, .. ]
91             #pod
92             #pod =head2 -also => ITEM
93             #pod
94             #pod =head2 -also => REGEX
95             #pod
96             #pod =head2 -also => SUB
97             #pod
98             #pod Sometimes you don't want to clean imports only, but also helper functions
99             #pod you're using in your methods. The C<-also> switch can be used to declare a list
100             #pod of functions that should be removed additional to any imports:
101             #pod
102             #pod use namespace::autoclean -also => ['some_function', 'another_function'];
103             #pod
104             #pod If only one function needs to be additionally cleaned the C<-also> switch also
105             #pod accepts a plain string:
106             #pod
107             #pod use namespace::autoclean -also => 'some_function';
108             #pod
109             #pod In some situations, you may wish for a more I<powerful> cleaning solution.
110             #pod
111             #pod The C<-also> switch can take a Regex or a CodeRef to match against local
112             #pod function names to clean.
113             #pod
114             #pod use namespace::autoclean -also => qr/^_/
115             #pod
116             #pod use namespace::autoclean -also => sub { $_ =~ m{^_} };
117             #pod
118             #pod use namespace::autoclean -also => [qr/^_/ , qr/^hidden_/ ];
119             #pod
120             #pod use namespace::autoclean -also => [sub { $_ =~ m/^_/ or $_ =~ m/^hidden/ }, sub { uc($_) == $_ } ];
121             #pod
122             #pod =head2 -except => [ ITEM | REGEX | SUB, .. ]
123             #pod
124             #pod =head2 -except => ITEM
125             #pod
126             #pod =head2 -except => REGEX
127             #pod
128             #pod =head2 -except => SUB
129             #pod
130             #pod This takes exactly the same options as C<-also> except that anything this
131             #pod matches will I<not> be cleaned.
132             #pod
133             #pod =head1 CAVEATS
134             #pod
135             #pod When used with L<Moo> classes, the heuristic used to check for methods won't
136             #pod work correctly for methods from roles consumed at compile time.
137             #pod
138             #pod package My::Class;
139             #pod use Moo;
140             #pod use namespace::autoclean;
141             #pod
142             #pod # Bad, any consumed methods will be cleaned
143             #pod BEGIN { with 'Some::Role' }
144             #pod
145             #pod # Good, methods from role will be maintained
146             #pod with 'Some::Role';
147             #pod
148             #pod Additionally, method detection may not work properly in L<Mouse> classes in
149             #pod perls earlier than 5.10.
150             #pod
151             #pod =head1 SEE ALSO
152             #pod
153             #pod =for :list
154             #pod * L<namespace::clean>
155             #pod * L<B::Hooks::EndOfScope>
156             #pod * L<namespace::sweep>
157             #pod * L<Sub::Exporter::ForMethods>
158             #pod * L<Sub::Name>
159             #pod * L<Sub::Install>
160             #pod * L<Test::CleanNamespaces>
161             #pod * L<Dist::Zilla::Plugin::Test::CleanNamespaces>
162             #pod
163             #pod =cut
164              
165             sub import {
166 18     18   27884 my ($class, %args) = @_;
167              
168             my $subcast = sub {
169 10     10   24 my $i = shift;
170 10 100       38 return $i if ref $i eq 'CODE';
171 8 100       34 return sub { $_ =~ $i } if ref $i eq 'Regexp';
  10         90  
172 5         25 return sub { $_ eq $i };
  11         131  
173 18         101 };
174              
175             my $runtest = sub {
176 27     27   58 my ($code, $method_name) = @_;
177 27         44 local $_ = $method_name;
178 27         60 return $code->();
179 18         70 };
180              
181 18 100       91 my $cleanee = exists $args{-cleanee} ? $args{-cleanee} : scalar caller;
182              
183             my @also = map $subcast->($_), (
184             exists $args{-also}
185 2         10 ? (ref $args{-also} eq 'ARRAY' ? @{ $args{-also} } : $args{-also})
186 18 100       90 : ()
    100          
187             );
188              
189             my @except = map $subcast->($_), (
190             exists $args{-except}
191 1         4 ? (ref $args{-except} eq 'ARRAY' ? @{ $args{-except} } : $args{-except})
192 18 100       57 : ()
    100          
193             );
194              
195             on_scope_end {
196 18     18   2490 my $subs = namespace::clean->get_functions($cleanee);
197 18         1593 my $method_check = _method_check($cleanee);
198              
199             my @clean = grep {
200 18         80 my $method = $_;
  87         300  
201 6         13 ! first { $runtest->($_, $method) } @except
202             and ( !$method_check->($method)
203 87 100 100     548 or first { $runtest->($_, $method) } @also)
  21         72  
204             } keys %$subs;
205              
206 18         152 namespace::clean->clean_subroutines($cleanee, @clean);
207 18         122 };
208             }
209              
210             sub _method_check {
211 18     18   43 my $package = shift;
212 18 50 33     150 if (
213             (defined &Class::MOP::class_of and my $meta = Class::MOP::class_of($package))
214             ) {
215 0         0 my %methods = map +($_ => 1), $meta->get_method_list;
216 0 0 0     0 $methods{meta} = 1
217             if $meta->isa('Moose::Meta::Role') && Moose->VERSION < 0.90;
218 0 0   0   0 return sub { $_[0] =~ /^\(/ || $methods{$_[0]} };
  0         0  
219             }
220             else {
221 18 50       323 my $does = $package->can('does') ? 'does'
    100          
222             : $package->can('DOES') ? 'DOES'
223             : undef;
224             return sub {
225 84 100   84   279 return 1 if $_[0] =~ /^\(/;
226 10     10   11286 my $coderef = do { no strict 'refs'; \&{ $package . '::' . $_[0] } };
  10         55  
  10         2409  
  79         129  
  79         127  
  79         275  
227 79         570 my ($code_stash) = subname($coderef) =~ /\A(.*)::/s;
228 79 100       491 return 1 if $code_stash eq $package;
229 39 50       98 return 1 if $code_stash eq 'constant';
230             # TODO: consider if we really need this eval
231 39 100 66     113 return 1 if $does && eval { $package->$does($code_stash) };
  39         199  
232 35         691 return 0;
233 18         172 };
234             }
235             }
236              
237             1;
238              
239             __END__
240              
241             =pod
242              
243             =encoding UTF-8
244              
245             =head1 NAME
246              
247             namespace::autoclean - Keep imports out of your namespace
248              
249             =head1 VERSION
250              
251             version 0.31
252              
253             =head1 SYNOPSIS
254              
255             package Foo;
256             use namespace::autoclean;
257             use Some::Package qw/imported_function/;
258              
259             sub bar { imported_function('stuff') }
260              
261             # later on:
262             Foo->bar; # works
263             Foo->imported_function; # will fail. imported_function got cleaned after compilation
264              
265             =head1 DESCRIPTION
266              
267             When you import a function into a Perl package, it will naturally also be
268             available as a method.
269              
270             The C<namespace::autoclean> pragma will remove all imported symbols at the end
271             of the current package's compile cycle. Functions called in the package itself
272             will still be bound by their name, but they won't show up as methods on your
273             class or instances.
274              
275             This module is very similar to L<namespace::clean|namespace::clean>, except it
276             will clean all imported functions, no matter if you imported them before or
277             after you C<use>d the pragma. It will also not touch anything that looks like a
278             method.
279              
280             If you're writing an exporter and you want to clean up after yourself (and your
281             peers), you can use the C<-cleanee> switch to specify what package to clean:
282              
283             package My::MooseX::namespace::autoclean;
284             use strict;
285              
286             use namespace::autoclean (); # no cleanup, just load
287              
288             sub import {
289             namespace::autoclean->import(
290             -cleanee => scalar(caller),
291             );
292             }
293              
294             =head1 WHAT IS AND ISN'T CLEANED
295              
296             C<namespace::autoclean> will leave behind anything that it deems a method. For
297             L<Moose> classes, this the based on the C<get_method_list> method
298             on from the L<Class::MOP::Class|metaclass>. For non-Moose classes, anything
299             defined within the package will be identified as a method. This should match
300             Moose's definition of a method. Additionally, the magic subs installed by
301             L<overload> will not be cleaned.
302              
303             =head1 PARAMETERS
304              
305             =head2 -also => [ ITEM | REGEX | SUB, .. ]
306              
307             =head2 -also => ITEM
308              
309             =head2 -also => REGEX
310              
311             =head2 -also => SUB
312              
313             Sometimes you don't want to clean imports only, but also helper functions
314             you're using in your methods. The C<-also> switch can be used to declare a list
315             of functions that should be removed additional to any imports:
316              
317             use namespace::autoclean -also => ['some_function', 'another_function'];
318              
319             If only one function needs to be additionally cleaned the C<-also> switch also
320             accepts a plain string:
321              
322             use namespace::autoclean -also => 'some_function';
323              
324             In some situations, you may wish for a more I<powerful> cleaning solution.
325              
326             The C<-also> switch can take a Regex or a CodeRef to match against local
327             function names to clean.
328              
329             use namespace::autoclean -also => qr/^_/
330              
331             use namespace::autoclean -also => sub { $_ =~ m{^_} };
332              
333             use namespace::autoclean -also => [qr/^_/ , qr/^hidden_/ ];
334              
335             use namespace::autoclean -also => [sub { $_ =~ m/^_/ or $_ =~ m/^hidden/ }, sub { uc($_) == $_ } ];
336              
337             =head2 -except => [ ITEM | REGEX | SUB, .. ]
338              
339             =head2 -except => ITEM
340              
341             =head2 -except => REGEX
342              
343             =head2 -except => SUB
344              
345             This takes exactly the same options as C<-also> except that anything this
346             matches will I<not> be cleaned.
347              
348             =head1 CAVEATS
349              
350             When used with L<Moo> classes, the heuristic used to check for methods won't
351             work correctly for methods from roles consumed at compile time.
352              
353             package My::Class;
354             use Moo;
355             use namespace::autoclean;
356              
357             # Bad, any consumed methods will be cleaned
358             BEGIN { with 'Some::Role' }
359              
360             # Good, methods from role will be maintained
361             with 'Some::Role';
362              
363             Additionally, method detection may not work properly in L<Mouse> classes in
364             perls earlier than 5.10.
365              
366             =head1 SEE ALSO
367              
368             =over 4
369              
370             =item *
371              
372             L<namespace::clean>
373              
374             =item *
375              
376             L<B::Hooks::EndOfScope>
377              
378             =item *
379              
380             L<namespace::sweep>
381              
382             =item *
383              
384             L<Sub::Exporter::ForMethods>
385              
386             =item *
387              
388             L<Sub::Name>
389              
390             =item *
391              
392             L<Sub::Install>
393              
394             =item *
395              
396             L<Test::CleanNamespaces>
397              
398             =item *
399              
400             L<Dist::Zilla::Plugin::Test::CleanNamespaces>
401              
402             =back
403              
404             =head1 SUPPORT
405              
406             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=namespace-autoclean>
407             (or L<bug-namespace-autoclean@rt.cpan.org|mailto:bug-namespace-autoclean@rt.cpan.org>).
408              
409             There is also a mailing list available for users of this distribution, at
410             L<http://lists.perl.org/list/moose.html>.
411              
412             There is also an irc channel available for users of this distribution, at
413             L<C<#moose> on C<irc.perl.org>|irc://irc.perl.org/#moose>.
414              
415             =head1 AUTHOR
416              
417             Florian Ragwitz <rafl@debian.org>
418              
419             =head1 CONTRIBUTORS
420              
421             =for stopwords Karen Etheridge Graham Knop Dave Rolsky Kent Fredric Tomas Doran Shawn M Moore Felix Ostmann Andrew Rodland Chris Prather
422              
423             =over 4
424              
425             =item *
426              
427             Karen Etheridge <ether@cpan.org>
428              
429             =item *
430              
431             Graham Knop <haarg@haarg.org>
432              
433             =item *
434              
435             Dave Rolsky <autarch@urth.org>
436              
437             =item *
438              
439             Kent Fredric <kentfredric@gmail.com>
440              
441             =item *
442              
443             Tomas Doran <bobtfish@bobtfish.net>
444              
445             =item *
446              
447             Shawn M Moore <cpan@sartak.org>
448              
449             =item *
450              
451             Felix Ostmann <sadrak@cpan.org>
452              
453             =item *
454              
455             Andrew Rodland <arodland@cpan.org>
456              
457             =item *
458              
459             Chris Prather <chris@prather.org>
460              
461             =back
462              
463             =head1 COPYRIGHT AND LICENCE
464              
465             This software is copyright (c) 2009 by Florian Ragwitz.
466              
467             This is free software; you can redistribute it and/or modify it under
468             the same terms as the Perl 5 programming language system itself.
469              
470             =cut