File Coverage

blib/lib/Module/Installed.pm
Criterion Covered Total %
statement 44 92 47.8
branch 21 60 35.0
condition n/a
subroutine 9 10 90.0
pod 2 2 100.0
total 76 164 46.3


line stmt bran cond sub pod time code
1             package Module::Installed;
2              
3             our $VERSION = '1.01';
4              
5 3     3   145808 use strict;
  3         21  
  3         89  
6 3     3   16 use warnings;
  3         5  
  3         84  
7              
8 3     3   16 use Carp qw(croak);
  3         6  
  3         166  
9 3     3   1340 use Data::Dumper;
  3         14000  
  3         168  
10 3     3   20 use Exporter qw(import);
  3         7  
  3         344  
11             our @EXPORT_OK = qw(
12             includes_installed
13             module_installed
14             );
15              
16             my $SEPARATOR;
17              
18             BEGIN {
19 3 50   3   33 if ($^O =~ /^(dos|os2)/i) {
    50          
20 0         0 $SEPARATOR = '\\';
21             } elsif ($^O =~ /^MacOS/i) {
22 0         0 $SEPARATOR = ':';
23             } else {
24 3         2607 $SEPARATOR = '/';
25             }
26             }
27              
28             sub includes_installed {
29 2     2 1 682 my $file = shift;
30              
31 2 100       9 my $PPI = $ENV{MI_TEST_PPI} ? $ENV{MI_TEST_PPI} : 'PPI';
32              
33 2 100       62 if (! -f $file) {
34 1         204 croak("includes_installed() requires a valid Perl file as a parameter...");
35             }
36              
37 1 50       7 if (! module_installed($PPI)) {
38 1         96 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) ? 1 : 0;
51             }
52              
53 0         0 return \%includes;
54             }
55             sub module_installed {
56 8     8 1 3149 my $name = shift;
57              
58             # convert Foo::Bar -> Foo/Bar.pm
59 8         16 my $name_pm;
60 8 50       57 if ($name =~ /\A\w+(?:::\w+)*\z/) {
61 8         33 ($name_pm = "$name.pm") =~ s!::!$SEPARATOR!g;
62             } else {
63 0         0 $name_pm = $name;
64             }
65              
66 8 100       37 return 1 if exists $INC{$name_pm};
67 5 100       11 return eval {_module_source($name_pm); 1 } ? 1 : 0;
  5         16  
  1         12  
68             }
69             sub _get_module_source {
70 0     0   0 my $name = shift;
71              
72             # convert Foo::Bar -> Foo/Bar.pm
73 0         0 my $name_pm;
74 0 0       0 if ($name =~ /\A\w+(?:::\w+)*\z/) {
75 0         0 ($name_pm = "$name.pm") =~ s!::!$SEPARATOR!g;
76             } else {
77 0         0 $name_pm = $name;
78             }
79              
80 0         0 return _module_source $name_pm;
81             }
82             sub _module_source {
83 5     5   11 my $name_pm = shift;
84              
85 5         13 for my $entry (@INC) {
86 54 50       99 next unless defined $entry;
87 54         107 my $ref = ref($entry);
88 54         79 my ($is_hook, @hook_res);
89 54 50       270 if ($ref eq 'ARRAY') {
    50          
    50          
90 0         0 $is_hook++;
91 0         0 @hook_res = $entry->[0]->($entry, $name_pm);
92             } elsif (UNIVERSAL::can($entry, 'INC')) {
93 0         0 $is_hook++;
94 0         0 @hook_res = $entry->INC($name_pm);
95             } elsif ($ref eq 'CODE') {
96 0         0 $is_hook++;
97 0         0 @hook_res = $entry->($entry, $name_pm);
98             } else {
99 54         111 my $path = "$entry$SEPARATOR$name_pm";
100 54 100       994 if (-f $path) {
101 1 50       49 open my($fh), "<", $path
102             or die "Can't locate $name_pm: $path: $!";
103 1         6 local $/;
104 1 50       239 return wantarray ? (scalar <$fh>, $path) : scalar <$fh>;
105             }
106             }
107              
108 53 50       175 if ($is_hook) {
109 0 0       0 next unless @hook_res;
110 0 0       0 my $prepend_ref; $prepend_ref = shift @hook_res if ref($hook_res[0]) eq 'SCALAR';
  0         0  
111 0 0       0 my $fh ; $fh = shift @hook_res if ref($hook_res[0]) eq 'GLOB';
  0         0  
112 0 0       0 my $code ; $code = shift @hook_res if ref($hook_res[0]) eq 'CODE';
  0         0  
113 0 0       0 my $code_state ; $code_state = shift @hook_res if @hook_res;
  0         0  
114 0 0       0 if ($fh) {
    0          
115 0         0 my $src = "";
116 0         0 local $_;
117 0         0 while (!eof($fh)) {
118 0         0 $_ = <$fh>;
119 0 0       0 if ($code) {
120 0         0 $code->($code, $code_state);
121             }
122 0         0 $src .= $_;
123             }
124 0 0       0 $src = $$prepend_ref . $src if $prepend_ref;
125 0 0       0 return wantarray ? ($src, $entry) : $src;
126             } elsif ($code) {
127 0         0 my $src = "";
128 0         0 local $_;
129 0         0 while ($code->($code, $code_state)) {
130 0         0 $src .= $_;
131             }
132 0 0       0 $src = $$prepend_ref . $src if $prepend_ref;
133 0 0       0 return wantarray ? ($src, $entry) : $src;
134             }
135             }
136             }
137              
138 4         76 die "Can't locate $name_pm in \@INC (\@INC contains: ".join(" ", @INC).")";
139             }
140             1;
141              
142             # ABSTRACT: Check if modules are installed
143              
144             __END__