File Coverage

blib/lib/Module/Want.pm
Criterion Covered Total %
statement 68 70 97.1
branch 27 32 84.3
condition 27 35 77.1
subroutine 14 14 100.0
pod 10 10 100.0
total 146 161 90.6


line stmt bran cond sub pod time code
1             package Module::Want;
2              
3 1     1   63255 use strict;
  1         2  
  1         69  
4             *normalize_ns = \&get_clean_ns; # do before warnings to prevent 'only used once' warning
5             *get_relative_path_of_ns = \&get_inc_key; # do before warnings to prevent 'only used once' warning
6 1     1   10 use warnings;
  1         3  
  1         699  
7              
8             $Module::Want::VERSION = '0.6';
9              
10             my %lookup;
11              
12             # Uncomment these 3 lines and ' # $tries{$ns}++;' in have_mod() for dev testing
13             # $Module::Want::DevTesting = 1;
14             # my %tries;
15             # sub _get_debugs_refs { return \%lookup, \%tries }
16              
17             my $ns_regexp = qr/[A-Za-z_][A-Za-z0-9_]*(?:(?:\:\:|\')[A-Za-z0-9_]+)*/;
18              
19 1     1 1 1094 sub get_ns_regexp { return $ns_regexp }
20              
21 42     42 1 4373 sub is_ns { $_[0] =~ m/\A$ns_regexp\z/ }
22              
23             sub get_all_use_require_in_text {
24 6     6 1 2854 return $_[0] =~ m/(?:^\s*|\;\s*|eval[^;]+)(?:use|require)\s+($ns_regexp)/g;
25             }
26              
27             sub get_inc_key {
28 14 50   14 1 29 return if !is_ns( $_[0] );
29              
30             # %INC keys are always unix format so no need for File::Spec
31             # if I've been misinformed of that fact then please let me know, thanks
32 14         25 my $key = $_[0] . '.pm';
33 14         71 $key =~ s{(?:\:\:|\')}{/}g;
34 14         76 return $key;
35             }
36              
37             sub distname2ns {
38 3     3 1 6 my ($node) = @_;
39 3         6 $node =~ s/-/::/g;
40 3         7 my $ns = get_clean_ns($node);
41 3 100       6 return $ns if is_ns($ns);
42 1         4 return;
43             }
44              
45             sub ns2distname {
46 3     3 1 7 my $node = get_clean_ns( $_[0] );
47 3 100       5 return if !is_ns($node);
48 2         6 $node =~ s/::/-/g;
49 2         6 return $node;
50             }
51              
52             sub get_clean_ns {
53 7     7 1 9 my $dirty = $_[0];
54 7         17 $dirty =~ s{^\s+}{};
55 7         14 $dirty =~ s{\s+$}{};
56 7         10 $dirty =~ s{\'}{::}g;
57 7         14 return $dirty;
58             }
59              
60             sub have_mod {
61 11     11 1 73 my ( $ns, $skip_cache ) = @_;
62 11   50     50 $skip_cache ||= 0;
63              
64 11 100       18 if ( !is_ns($ns) ) {
65 1         8 require Carp;
66 1         5 Carp::carp('Invalid Namespace');
67 1         478 return;
68             }
69              
70 10 100 66     59 if ( $skip_cache || !exists $lookup{$ns} ) {
71              
72 4         9 $lookup{$ns} = 0;
73              
74             # $tries{$ns}++;
75 4         15 local $SIG{__DIE__}; # prevent benign eval from tripping potentially fatal sig handler
76 4         312 eval qq{require $ns;\$lookup{\$ns}++;}; ## no critic
77             }
78              
79 10 100       47 return $lookup{$ns} if $lookup{$ns};
80 3         14 return;
81             }
82              
83             sub get_inc_path_via_have_mod {
84 2     2 1 4 my ( $ns, $skip_cache ) = @_;
85 2 100       5 return unless have_mod( $ns, $skip_cache );
86 1         3 return $INC{ get_inc_key($ns) };
87             }
88              
89             sub search_inc_paths {
90 4     4 1 3746 my ( $ns, $want_abs ) = @_;
91              
92 4 50       9 have_mod('File::Spec') || return;
93              
94 4         9 my $rel_path = File::Spec->catfile( split( m{/}, get_relative_path_of_ns($ns) ) );
95 4 100       12 my $return_first = wantarray ? 0 : 1;
96 4         4 my @result;
97              
98 4         8 for my $path (@INC) {
99 12         150 my $abspath = File::Spec->rel2abs( $rel_path, $path );
100 12 100       214 if ( -f $abspath ) {
101 6 100       14 push @result, ( $want_abs ? $abspath : $path );
102 6 100       12 last if $return_first;
103             }
104             }
105              
106 4 50       11 if (@result) {
107 4 100       11 return $result[0] if $return_first;
108 2         9 return @result;
109             }
110 0         0 return;
111             }
112              
113             sub import {
114 6     6   15 shift;
115              
116 6         10 my $caller = caller();
117              
118 1     1   5 no strict 'refs'; ## no critic
  1         4  
  1         154  
119 6         12 *{ $caller . '::have_mod' } = \&have_mod;
  6         17  
120              
121 6         18 for my $ns (@_) {
122 8 50       15 next if $ns eq 'have_mod';
123              
124 8 50 100     128 if ( $ns eq 'is_ns' || $ns eq 'get_inc_key' || $ns eq 'get_clean_ns' || $ns eq 'get_ns_regexp' || $ns eq 'get_all_use_require_in_text' || $ns eq 'get_relative_path_of_ns' || $ns eq 'normalize_ns' || $ns eq 'get_inc_path_via_have_mod' || $ns eq 'search_inc_paths' || $ns eq 'distname2ns' || $ns eq 'ns2distname' ) {
      66        
      66        
      33        
      66        
      100        
      100        
      100        
      100        
      66        
125 8         8 *{ $caller . "::$ns" } = \&{$ns};
  8         37  
  8         16  
126             }
127             else {
128 0           have_mod($ns);
129             }
130             }
131             }
132              
133             1;
134              
135             __END__