File Coverage

blib/lib/Module/Installed.pm
Criterion Covered Total %
statement 51 99 51.5
branch 27 66 40.9
condition n/a
subroutine 9 10 90.0
pod 2 2 100.0
total 89 177 50.2


line stmt bran cond sub pod time code
1             package Module::Installed;
2              
3             our $VERSION = '1.02';
4              
5 5     5   266903 use strict;
  5         40  
  5         146  
6 5     5   24 use warnings;
  5         9  
  5         137  
7              
8 5     5   25 use Carp qw(croak);
  5         9  
  5         267  
9 5     5   2482 use Data::Dumper;
  5         25980  
  5         285  
10 5     5   34 use Exporter qw(import);
  5         7  
  5         524  
11             our @EXPORT_OK = qw(
12             includes_installed
13             module_installed
14             );
15              
16             my $SEPARATOR;
17              
18             BEGIN {
19 5 50   5   54 if ($^O =~ /^(dos|os2)/i) {
    50          
20 0         0 $SEPARATOR = '\\';
21             } elsif ($^O =~ /^MacOS/i) {
22 0         0 $SEPARATOR = ':';
23             } else {
24 5         4460 $SEPARATOR = '/';
25             }
26             }
27              
28             sub includes_installed {
29 2     2 1 728 my ($file, $cb) = @_;
30              
31 2 100       9 my $PPI = $ENV{MI_TEST_PPI} ? $ENV{MI_TEST_PPI} : 'PPI';
32              
33 2 100       57 if (! -f $file) {
34 1         205 croak("includes_installed() requires a valid Perl file as a parameter...");
35             }
36              
37 1 50       5 if (! module_installed($PPI)) {
38 1         112 croak("includes_installed() requires PPI, which isn't installed...");
39             }
40              
41 0         0 require PPI;
42 0         0 PPI->import;
43              
44 0         0 my $doc = PPI::Document->new($file);
45 0         0 my $includes = $doc->find('PPI::Statement::Include');
46              
47 0         0 my %includes;
48              
49 0         0 for (@$includes) {
50 0 0       0 $includes{$_->module} = module_installed($_->module, $cb) ? 1 : 0;
51             }
52              
53 0         0 return \%includes;
54             }
55             sub module_installed {
56 15     15 1 5358 my ($name, $sub) = @_;
57              
58             # convert Foo::Bar -> Foo/Bar.pm
59 15         24 my $name_pm;
60 15 50       101 if ($name =~ /\A\w+(?:::\w+)*\z/) {
61 15         54 ($name_pm = "$name.pm") =~ s!::!$SEPARATOR!g;
62             } else {
63 0         0 $name_pm = $name;
64             }
65              
66 15         21 my $installed = 0;
67              
68 15 100       40 if (exists $INC{$name_pm}) {
    100          
    100          
69 6         8 $installed = 1;
70             }
71 9         36 elsif (eval {_module_source($name_pm); 1 } ? 1 : 0) {
  2         15  
72 2         4 $installed = 1;
73             }
74              
75 15 100       39 if (defined $sub) {
76 6 100       14 if (ref $sub ne 'CODE') {
77 1         170 croak("Callback parameter to module_installed() must be a code ref")
78             }
79 5         16 $sub->($name, $name_pm, $installed);
80             }
81              
82 14         64 return $installed;
83             }
84             sub _get_module_source {
85 0     0   0 my $name = shift;
86              
87             # convert Foo::Bar -> Foo/Bar.pm
88 0         0 my $name_pm;
89 0 0       0 if ($name =~ /\A\w+(?:::\w+)*\z/) {
90 0         0 ($name_pm = "$name.pm") =~ s!::!$SEPARATOR!g;
91             } else {
92 0         0 $name_pm = $name;
93             }
94              
95 0         0 return _module_source $name_pm;
96             }
97             sub _module_source {
98 9     9   17 my $name_pm = shift;
99              
100 9         20 for my $entry (@INC) {
101 97 50       159 next unless defined $entry;
102 97         149 my $ref = ref($entry);
103 97         117 my ($is_hook, @hook_res);
104 97 50       512 if ($ref eq 'ARRAY') {
    50          
    50          
105 0         0 $is_hook++;
106 0         0 @hook_res = $entry->[0]->($entry, $name_pm);
107             } elsif (UNIVERSAL::can($entry, 'INC')) {
108 0         0 $is_hook++;
109 0         0 @hook_res = $entry->INC($name_pm);
110             } elsif ($ref eq 'CODE') {
111 0         0 $is_hook++;
112 0         0 @hook_res = $entry->($entry, $name_pm);
113             } else {
114 97         184 my $path = "$entry$SEPARATOR$name_pm";
115 97 100       1226 if (-f $path) {
116 2 50       69 open my($fh), "<", $path
117             or die "Can't locate $name_pm: $path: $!";
118 2         9 local $/;
119 2 50       440 return wantarray ? (scalar <$fh>, $path) : scalar <$fh>;
120             }
121             }
122              
123 95 50       231 if ($is_hook) {
124 0 0       0 next unless @hook_res;
125 0 0       0 my $prepend_ref; $prepend_ref = shift @hook_res if ref($hook_res[0]) eq 'SCALAR';
  0         0  
126 0 0       0 my $fh ; $fh = shift @hook_res if ref($hook_res[0]) eq 'GLOB';
  0         0  
127 0 0       0 my $code ; $code = shift @hook_res if ref($hook_res[0]) eq 'CODE';
  0         0  
128 0 0       0 my $code_state ; $code_state = shift @hook_res if @hook_res;
  0         0  
129 0 0       0 if ($fh) {
    0          
130 0         0 my $src = "";
131 0         0 local $_;
132 0         0 while (!eof($fh)) {
133 0         0 $_ = <$fh>;
134 0 0       0 if ($code) {
135 0         0 $code->($code, $code_state);
136             }
137 0         0 $src .= $_;
138             }
139 0 0       0 $src = $$prepend_ref . $src if $prepend_ref;
140 0 0       0 return wantarray ? ($src, $entry) : $src;
141             } elsif ($code) {
142 0         0 my $src = "";
143 0         0 local $_;
144 0         0 while ($code->($code, $code_state)) {
145 0         0 $src .= $_;
146             }
147 0 0       0 $src = $$prepend_ref . $src if $prepend_ref;
148 0 0       0 return wantarray ? ($src, $entry) : $src;
149             }
150             }
151             }
152              
153 7         87 die "Can't locate $name_pm in \@INC (\@INC contains: ".join(" ", @INC).")";
154             }
155             1;
156              
157             # ABSTRACT: Check if modules are installed
158              
159             __END__