File Coverage

blib/lib/Module/Util/Masked.pm
Criterion Covered Total %
statement 63 71 88.7
branch 21 34 61.7
condition 10 15 66.6
subroutine 12 12 100.0
pod 0 3 0.0
total 106 135 78.5


line stmt bran cond sub pod time code
1             # Copyright 2010, 2011, 2012, 2015, 2017 Kevin Ryde
2              
3             # This file is part of Test-VariousBits.
4             #
5             # Test-VariousBits is free software; you can redistribute it and/or
6             # modify it under the terms of the GNU General Public License as published
7             # by the Free Software Foundation; either version 3, or (at your option) any
8             # later version.
9             #
10             # Test-VariousBits is distributed in the hope that it will be useful,
11             # but WITHOUT ANY WARRANTY; without even the implied warranty of
12             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13             # Public License for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Test-VariousBits. If not, see .
17              
18             package Module::Util::Masked;
19             require 5;
20 2     2   522349 use strict;
  2         5  
  2         194  
21              
22 2     2   17 use vars qw($VERSION);
  2         4  
  2         181  
23             $VERSION = 8;
24              
25             # uncomment this to run the ### lines
26             # use Smart::Comments;
27              
28             # BEGIN {
29             # # Check that Module::Util isn't already loaded.
30             # #
31             # # is_valid_module_name() here is a representative func, and not one that's
32             # # mangled here (so as not to risk hitting that if something goes badly
33             # # wrong). Maybe looking at %INC would be better.
34             # #
35             # if (Module::Util->can('is_valid_module_name')) {
36             # die "Module::Util already loaded, cannot fake after imports may have grabbed its functions";
37             # }
38             # }
39              
40 2     2   14 use Module::Util;
  2         4  
  2         1258  
41              
42             # Crib notes:
43             #
44             # Module::Util uses File::Find which loads Scalar::Util, so the requires of
45             # that here are unnecessary, but included for certainty.
46              
47              
48              
49              
50             sub _module_is_unplugged {
51 24     24   48 my ($module) = @_;
52 24 50       159 if (Devel::Unplug->can('unplugged')) {
53 0         0 foreach my $unplugged (Devel::Unplug::unplugged()) {
54 0 0       0 if (ref $unplugged ? $module =~ $unplugged : $module eq $unplugged) {
    0          
55 0         0 return 1;
56             }
57             }
58             }
59 24         74 return 0;
60             }
61              
62             sub _incval_masks_module {
63 115     115   253 my ($incval, $module) = @_;
64             ### _incval_masks_module() ...
65             ### $incval
66             ### $module
67              
68 115 100       359 ref $incval or return 0;
69              
70 19 50       75 if ($incval == \&Test::Without::Module::fake_module) {
71             ### incval is Test-Without-Module fake_module ...
72 0         0 my $href = Test::Without::Module::get_forbidden_list();
73             ### $href
74              
75             # Test::Without::Module 0.18 and earlier had Foo::Bar module name
76             # Test::Without::Module 0.20 has Foo/Bar.pm path
77             # look for either
78 0 0 0     0 if (exists $href->{$module}
79             || exists $href->{Module::Util::module_path($module)}) {
80             ### Test-Without-Module masks ...
81 0         0 return 1;
82             }
83             }
84              
85 19         116 require Scalar::Util;
86 19 100 66     138 if (Scalar::Util::blessed($incval)
      100        
87             && $incval->isa('Module::Mask')
88             && $incval->is_masked($module)) {
89             ### Module-Mask masks ...
90 10         594 return 1;
91             }
92              
93             ### not masked ...
94 9         351 return 0;
95             }
96              
97             # _pruned_inc($module) using @INC
98             # _pruned_inc($module, $dir,$dir,...)
99             # Return list of dirs preceding any mask of $module.
100             #
101             sub _pruned_inc {
102 14     14   27 my $module = shift;
103 14 50       68 my @inc = @_ ? @_ : @INC;
104             ### _pruned_inc() ...
105              
106 14         43 foreach my $pos (0 .. $#inc) {
107 107 100       238 if (_incval_masks_module($inc[$pos],$module)) {
108 5         31 $#inc = $pos-1; # truncate
109 5 100       13 if ($pos == 0) {
110 2         13 return;
111             }
112 3         7 $#inc = $pos-1;
113 3         7 last;
114             }
115             }
116             ### pruned to: @inc
117 12         82 return @inc;
118             }
119              
120             {
121             my $orig = \&Module::Util::find_installed;
122              
123             sub Module_Util_Masked__find_installed ($;@) {
124 5     5 0 1178 my $module = shift;
125             ### M-U-Masked find_installed(): $module
126              
127 5 50       14 if (_module_is_unplugged($module)) {
128 0         0 return undef;
129             }
130 5 100       14 my @inc = _pruned_inc($module, @_)
131             or return undef; # nothing after pruned
132             ### @inc
133 4         52 return &$orig($module,@inc);
134             }
135 2     2   19 no warnings 'redefine';
  2         19  
  2         438  
136             *Module::Util::find_installed = \&Module_Util_Masked__find_installed;
137             }
138              
139             {
140             my $orig = \&Module::Util::all_installed;
141              
142             sub Module_Util_Masked__all_installed ($;@) {
143 5     5 0 2206 my $module = shift;
144             ### M-U-Masked all_installed(): $module
145              
146 5 50       23 if (_module_is_unplugged($module)) {
147 0         0 return;
148             }
149 5 100       16 my @inc = _pruned_inc($module, @_)
150             or return; # nothing after pruned
151 4         13 return &$orig($module,_pruned_inc($module, @_));
152             }
153 2     2   18 no warnings 'redefine';
  2         5  
  2         841  
154             *Module::Util::all_installed = \&Module_Util_Masked__all_installed;
155             }
156              
157             {
158             my $orig = \&Module::Util::find_in_namespace;
159              
160             sub Module_Util_Masked__find_in_namespace ($;@) {
161 7     7 0 1484 my $namespace = shift;
162             ### M-U-Masked find_in_namespace(): $namespace
163              
164 7         16 my @masks;
165             my @ret;
166 7 50       24 foreach my $incval (@_ ? @_ : @INC) {
167 70 100 100     235 if (ref $incval
168             && do {
169 6         40 require Scalar::Util;
170 6 50 66     69 (Scalar::Util::refaddr($incval)
171             == \&Test::Without::Module::fake_module
172             || (Scalar::Util::blessed($incval)
173             && $incval->isa('Module::Mask')))
174             }) {
175 5         13 push @masks, $incval;
176             } else {
177 65         173 my @found = &$orig($namespace, $incval);
178 65         21048 @found = grep {! _module_is_unplugged($_)} @found;
  14         34  
179 65         157 foreach my $mask (@masks) {
180 36         93 @found = grep {! _incval_masks_module($mask,$_)} @found;
  8         19  
181             }
182 65         156 push @ret, @found;
183             }
184             }
185             ### ret inc duplicates: @ret
186 7         14 my %seen;
187 7         19 return grep { !$seen{$_}++ } @ret;
  9         52  
188             }
189 2     2   17 no warnings 'redefine';
  2         5  
  2         207  
190             *Module::Util::find_in_namespace = \&Module_Util_Masked__find_in_namespace;
191             }
192              
193             1;
194             __END__