| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Module::Path; | 
| 2 |  |  |  |  |  |  | # ABSTRACT: get the full path to a locally installed module | 
| 3 |  |  |  |  |  |  | $Module::Path::VERSION = '0.19'; | 
| 4 | 2 |  |  | 2 |  | 15801 | use 5.006; | 
|  | 2 |  |  |  |  | 6 |  | 
|  | 2 |  |  |  |  | 63 |  | 
| 5 | 2 |  |  | 2 |  | 8 | use strict; | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 55 |  | 
| 6 | 2 |  |  | 2 |  | 15 | use warnings; | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 57 |  | 
| 7 | 2 |  |  | 2 |  | 8 | use File::Basename 'dirname'; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 169 |  | 
| 8 | 2 |  |  | 2 |  | 8 | use Cwd qw/ abs_path /; | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 507 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | require Exporter; | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | our @ISA       = qw(Exporter); | 
| 13 |  |  |  |  |  |  | our @EXPORT_OK = qw(module_path); | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | my $SEPARATOR; | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | BEGIN { | 
| 18 | 2 | 50 |  | 2 |  | 23 | if ($^O =~ /^(dos|os2)/i) { | 
|  |  | 50 |  |  |  |  |  | 
| 19 | 0 |  |  |  |  | 0 | $SEPARATOR = '\\'; | 
| 20 |  |  |  |  |  |  | } elsif ($^O =~ /^MacOS/i) { | 
| 21 | 0 |  |  |  |  | 0 | $SEPARATOR = ':'; | 
| 22 |  |  |  |  |  |  | } else { | 
| 23 | 2 |  |  |  |  | 385 | $SEPARATOR = '/'; | 
| 24 |  |  |  |  |  |  | } | 
| 25 |  |  |  |  |  |  | } | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | sub module_path | 
| 28 |  |  |  |  |  |  | { | 
| 29 | 3 |  |  | 3 | 0 | 82 | my $module = shift; | 
| 30 | 3 |  |  |  |  | 3 | my $relpath; | 
| 31 |  |  |  |  |  |  | my $fullpath; | 
| 32 |  |  |  |  |  |  |  | 
| 33 | 3 |  |  |  |  | 8 | ($relpath = $module) =~ s/::/$SEPARATOR/g; | 
| 34 | 3 | 100 |  |  |  | 12 | $relpath .= '.pm' unless $relpath =~ m!\.pm$!; | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | DIRECTORY: | 
| 37 | 3 |  |  |  |  | 6 | foreach my $dir (@INC) { | 
| 38 | 31 | 50 |  |  |  | 44 | next DIRECTORY if not defined($dir); | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | # see 'perldoc -f require' on why you might find | 
| 41 |  |  |  |  |  |  | # a reference in @INC | 
| 42 | 31 | 50 |  |  |  | 40 | next DIRECTORY if ref($dir); | 
| 43 |  |  |  |  |  |  |  | 
| 44 | 31 | 50 | 33 |  |  | 624 | next unless -d $dir && -x $dir; | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | # The directory path might have a symlink somewhere in it, | 
| 47 |  |  |  |  |  |  | # so we get an absolute path (ie resolve any symlinks). | 
| 48 |  |  |  |  |  |  | # The previous attempt at this only dealt with the case | 
| 49 |  |  |  |  |  |  | # where the final directory in the path was a symlink, | 
| 50 |  |  |  |  |  |  | # now we're trying to deal with symlinks anywhere in the path. | 
| 51 | 31 |  |  |  |  | 32 | my $abs_dir = $dir; | 
| 52 | 31 |  |  |  |  | 23 | eval { $abs_dir = abs_path($abs_dir); }; | 
|  | 31 |  |  |  |  | 963 |  | 
| 53 | 31 | 50 | 33 |  |  | 100 | next DIRECTORY if $@ || !defined($abs_dir); | 
| 54 |  |  |  |  |  |  |  | 
| 55 | 31 |  |  |  |  | 38 | $fullpath = $abs_dir.$SEPARATOR.$relpath; | 
| 56 | 31 | 100 |  |  |  | 300 | return $fullpath if -f $fullpath; | 
| 57 |  |  |  |  |  |  | } | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 1 |  |  |  |  | 6 | return undef; | 
| 60 |  |  |  |  |  |  | } | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | 1; | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | =head1 NAME | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | Module::Path - get the full path to a locally installed module | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | use Module::Path 'module_path'; | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | $path = module_path('Test::More'); | 
| 73 |  |  |  |  |  |  | if (defined($path)) { | 
| 74 |  |  |  |  |  |  | print "Test::More found at $path\n"; | 
| 75 |  |  |  |  |  |  | } else { | 
| 76 |  |  |  |  |  |  | print "Danger Will Robinson!\n"; | 
| 77 |  |  |  |  |  |  | } | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | This module provides a single function, C, | 
| 82 |  |  |  |  |  |  | which takes a module name and finds the first directory in your C<@INC> path | 
| 83 |  |  |  |  |  |  | where the module is installed locally. | 
| 84 |  |  |  |  |  |  | It returns the full path to that file, resolving any symlinks. | 
| 85 |  |  |  |  |  |  | It is portable and only depends on core modules. | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | It works by looking in all the directories in C<@INC> | 
| 88 |  |  |  |  |  |  | for an appropriately named file: | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | =over 4 | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | =item | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | Foo::Bar becomes C, using the correct directory path | 
| 95 |  |  |  |  |  |  | separator for your operating system. | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | =item | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | Iterate over C<@INC>, ignoring any references | 
| 100 |  |  |  |  |  |  | (see L<"perlfunc"/"require"> if you're surprised to hear | 
| 101 |  |  |  |  |  |  | that you might find references in C<@INC>). | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | =item | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | For each directory in C<@INC>, append the partial path (C), | 
| 106 |  |  |  |  |  |  | again using the correct directory path separator. | 
| 107 |  |  |  |  |  |  | If the resulting file exists, return this path. | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | =item | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | If a directory in C<@INC> is a symlink, then we resolve the path, | 
| 112 |  |  |  |  |  |  | and return a path containing the linked-to directory. | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | =item | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | If no file was found, return C. | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | =back | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | I wrote this module because I couldn't find an alternative | 
| 121 |  |  |  |  |  |  | which dealt with the points listed above, and didn't pull in | 
| 122 |  |  |  |  |  |  | what seemed like too many dependencies to me. | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | The distribution for C includes the C | 
| 125 |  |  |  |  |  |  | script, which lets you get the path for a module from the command-line: | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | % mpath Module::Path | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | The C function will also cope if the module name includes C<.pm>; | 
| 130 |  |  |  |  |  |  | this means you can pass a partial path, such as used as the keys in C<%INC>: | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | module_path('Test/More.pm') eq $INC{'Test/More.pm'} | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | The above is the basis for one of the tests. | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | =head1 BUGS | 
| 137 |  |  |  |  |  |  |  | 
| 138 |  |  |  |  |  |  | Obviously this only works where the module you're after has its own C<.pm> | 
| 139 |  |  |  |  |  |  | file. If a file defines multiple packages, this won't work. | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | This also won't find any modules that are being loaded in some special | 
| 142 |  |  |  |  |  |  | way, for example using a code reference in C<@INC>, as described | 
| 143 |  |  |  |  |  |  | in L<"perlfunc"/"require">. | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | There are a number of other modules on CPAN which provide the | 
| 149 |  |  |  |  |  |  | same or similar functionality: | 
| 150 |  |  |  |  |  |  | L, | 
| 151 |  |  |  |  |  |  | L, | 
| 152 |  |  |  |  |  |  | L, | 
| 153 |  |  |  |  |  |  | L, | 
| 154 |  |  |  |  |  |  | L, | 
| 155 |  |  |  |  |  |  | L, | 
| 156 |  |  |  |  |  |  | L, | 
| 157 |  |  |  |  |  |  | L, | 
| 158 |  |  |  |  |  |  | L, | 
| 159 |  |  |  |  |  |  | L, | 
| 160 |  |  |  |  |  |  | L, | 
| 161 |  |  |  |  |  |  | and L. | 
| 162 |  |  |  |  |  |  |  | 
| 163 |  |  |  |  |  |  | I've written a review of all such modules that I'm aware of: | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | =over 4 | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | L | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | =back | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | Module::Path was written to be fast, portable, and have a low number of | 
| 172 |  |  |  |  |  |  | core-only runtime dependencies. It you only want to look up the path to | 
| 173 |  |  |  |  |  |  | a module, it's a good choice. | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | If you want more information, such as the module's version, what functions | 
| 176 |  |  |  |  |  |  | are provided, etc, then start by looking at L, | 
| 177 |  |  |  |  |  |  | L, and L. | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | The following scripts can also give you the path: | 
| 180 |  |  |  |  |  |  | L, | 
| 181 |  |  |  |  |  |  | L. | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | =head1 REPOSITORY | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | L | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | =head1 AUTHOR | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | Neil Bowers Eneilb@cpan.orgE | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | This software is copyright (c) 2012 by Neil Bowers . | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | This is free software; you can redistribute it and/or modify it under | 
| 197 |  |  |  |  |  |  | the same terms as the Perl 5 programming language system itself. | 
| 198 |  |  |  |  |  |  |  |