1 package Module::Load::Conditional;
6 use Params::Check qw[check];
7 use Locale::Maketext::Simple Style => 'gettext';
14 use Module::Metadata ();
16 use constant ON_VMS => $^O eq 'VMS';
19 use vars qw[ $VERSION @ISA $VERBOSE $CACHE @EXPORT_OK $DEPRECATED
20 $FIND_VERSION $ERROR $CHECK_INC_HASH];
28 @EXPORT_OK = qw[check_install can_load requires];
35 Module::Load::Conditional - Looking up module information / loading at runtime
39 use Module::Load::Conditional qw[can_load check_install requires];
45 'Test::More' => undef,
48 print can_load( modules => $use_list )
49 ? 'all modules loaded successfully'
50 : 'failed to load required modules';
53 my $rv = check_install( module => 'LWP', version => 5.60 )
54 or print 'LWP is not installed!';
56 print 'LWP up to date' if $rv->{uptodate};
57 print "LWP version is $rv->{version}\n";
58 print "LWP is installed as file $rv->{file}\n";
61 print "LWP requires the following modules to be installed:\n";
62 print join "\n", requires('LWP');
64 ### allow M::L::C to peek in your %INC rather than just
66 $Module::Load::Conditional::CHECK_INC_HASH = 1;
68 ### reset the 'can_load' cache
69 undef $Module::Load::Conditional::CACHE;
71 ### don't have Module::Load::Conditional issue warnings --
73 $Module::Load::Conditional::VERBOSE = 0;
75 ### The last error that happened during a call to 'can_load'
76 my $err = $Module::Load::Conditional::ERROR;
81 Module::Load::Conditional provides simple ways to query and possibly load any of
82 the modules you have installed on your system during runtime.
84 It is able to load multiple modules at once or none at all if one of
85 them was not able to load. It also takes care of any error checking
90 =head2 $href = check_install( module => NAME [, version => VERSION, verbose => BOOL ] );
92 C<check_install> allows you to verify if a certain module is installed
93 or not. You may call it with the following arguments:
99 The name of the module you wish to verify -- this is a required key
103 The version this module needs to be -- this is optional
107 Whether or not to be verbose about what it is doing -- it will default
108 to $Module::Load::Conditional::VERBOSE
112 It will return undef if it was not able to find where the module was
113 installed, or a hash reference with the following keys if it was able
120 Full path to the file that contains the module
124 Directory, or more exact the C<@INC> entry, where the module was
129 The version number of the installed module - this will be C<undef> if
130 the module had no (or unparsable) version number, or if the variable
131 C<$Module::Load::Conditional::FIND_VERSION> was set to true.
132 (See the C<GLOBAL VARIABLES> section below for details)
136 A boolean value indicating whether or not the module was found to be
137 at least the version you specified. If you did not specify a version,
138 uptodate will always be true if the module was found.
139 If no parsable version was found in the module, uptodate will also be
140 true, since C<check_install> had no way to verify clearly.
142 See also C<$Module::Load::Conditional::DEPRECATED>, which affects
143 the outcome of this value.
149 ### this checks if a certain module is installed already ###
150 ### if it returns true, the module in question is already installed
151 ### or we found the file, but couldn't open it, OR there was no version
152 ### to be found in the module
153 ### it will return 0 if the version in the module is LOWER then the one
154 ### we are looking for, or if we couldn't find the desired module to begin with
155 ### if the installed version is higher or equal to the one we want, it will return
156 ### a hashref with he module name and version in it.. so 'true' as well.
161 version => { default => '0.0' },
162 module => { required => 1 },
163 verbose => { default => $VERBOSE },
167 unless( $args = check( $tmpl, \%hash, $VERBOSE ) ) {
168 warn loc( q[A problem occurred checking arguments] ) if $VERBOSE;
172 my $file = File::Spec->catfile( split /::/, $args->{module} ) . '.pm';
173 my $file_inc = File::Spec::Unix->catfile(
174 split /::/, $args->{module}
177 ### where we store the return value ###
186 ### check the inc hash if we're allowed to
187 if( $CHECK_INC_HASH ) {
188 $filename = $href->{'file'} =
189 $INC{ $file_inc } if defined $INC{ $file_inc };
191 ### find the version by inspecting the package
192 if( defined $filename && $FIND_VERSION ) {
194 $href->{version} = ${ "$args->{module}"."::VERSION" };
198 ### we didnt find the filename yet by looking in %INC,
200 unless( $filename ) {
202 DIR: for my $dir ( @INC ) {
207 ### @INC hook -- we invoke it and get the filehandle back
208 ### this is actually documented behaviour as of 5.8 ;)
210 my $existed_in_inc = $INC{$file_inc};
212 if (UNIVERSAL::isa($dir, 'CODE')) {
213 ($fh) = $dir->($dir, $file);
215 } elsif (UNIVERSAL::isa($dir, 'ARRAY')) {
216 ($fh) = $dir->[0]->($dir, $file, @{$dir}{1..$#{$dir}})
218 } elsif (UNIVERSAL::can($dir, 'INC')) {
219 ($fh) = $dir->INC($file);
222 if (!UNIVERSAL::isa($fh, 'GLOB')) {
223 warn loc(q[Cannot open file '%1': %2], $file, $!)
228 $filename = $INC{$file_inc} || $file;
230 delete $INC{$file_inc} if not $existed_in_inc;
233 $filename = File::Spec->catfile($dir, $file);
234 next unless -e $filename;
236 $fh = new FileHandle;
237 if (!$fh->open($filename)) {
238 warn loc(q[Cannot open file '%1': %2], $file, $!)
244 ### store the directory we found the file in
247 ### files need to be in unix format under vms,
248 ### or they might be loaded twice
249 $href->{file} = ON_VMS
250 ? VMS::Filespec::unixify( $filename )
253 ### if we don't need the version, we're done
254 last DIR unless $FIND_VERSION;
256 ### otherwise, the user wants us to find the version from files
257 my $mod_info = Module::Metadata->new_from_handle( $fh, $filename );
258 my $ver = $mod_info->version( $args->{module} );
261 $href->{version} = $ver;
268 ### if we couldn't find the file, return undef ###
269 return unless defined $href->{file};
271 ### only complain if we're expected to find a version higher than 0.0 anyway
272 if( $FIND_VERSION and not defined $href->{version} ) {
273 { ### don't warn about the 'not numeric' stuff ###
276 ### if we got here, we didn't find the version
277 warn loc(q[Could not check version on '%1'], $args->{module} )
278 if $args->{verbose} and $args->{version} > 0;
280 $href->{uptodate} = 1;
283 ### don't warn about the 'not numeric' stuff ###
286 ### use qv(), as it will deal with developer release number
287 ### ie ones containing _ as well. This addresses bug report
288 ### #29348: Version compare logic doesn't handle alphas?
290 ### Update from JPeacock: apparently qv() and version->new
291 ### are different things, and we *must* use version->new
292 ### here, or things like #30056 might start happening
294 ### We have to wrap this in an eval as version-0.82 raises
295 ### exceptions and not warnings now *sigh*
300 version->new( $args->{version} ) <= version->new( $href->{version} )
307 if ( $DEPRECATED and "$]" >= 5.011 ) {
308 require Module::CoreList;
311 $href->{uptodate} = 0 if
312 exists $Module::CoreList::version{ 0+$] }{ $args->{module} } and
313 Module::CoreList::is_deprecated( $args->{module} ) and
314 $Config::Config{privlibexp} eq $href->{dir};
320 =head2 $bool = can_load( modules => { NAME => VERSION [,NAME => VERSION] }, [verbose => BOOL, nocache => BOOL] )
322 C<can_load> will take a list of modules, optionally with version
323 numbers and determine if it is able to load them. If it can load *ALL*
324 of them, it will. If one or more are unloadable, none will be loaded.
326 This is particularly useful if you have More Than One Way (tm) to
327 solve a problem in a program, and only wish to continue down a path
328 if all modules could be loaded, and not load them if they couldn't.
330 This function uses the C<load> function from Module::Load under the
333 C<can_load> takes the following arguments:
339 This is a hashref of module/version pairs. The version indicates the
340 minimum version to load. If no version is provided, any version is
341 assumed to be good enough.
345 This controls whether warnings should be printed if a module failed
347 The default is to use the value of $Module::Load::Conditional::VERBOSE.
351 C<can_load> keeps its results in a cache, so it will not load the
352 same module twice, nor will it attempt to load a module that has
353 already failed to load before. By default, C<can_load> will check its
354 cache, but you can override that by setting C<nocache> to true.
362 modules => { default => {}, strict_type => 1 },
363 verbose => { default => $VERBOSE },
364 nocache => { default => 0 },
369 unless( $args = check( $tmpl, \%hash, $VERBOSE ) ) {
370 $ERROR = loc(q[Problem validating arguments!]);
371 warn $ERROR if $VERBOSE;
375 ### layout of $CACHE:
380 ### file => /path/to/file,
384 $CACHE ||= {}; # in case it was undef'd
388 my $href = $args->{modules};
391 for my $mod ( keys %$href ) {
393 next if $CACHE->{$mod}->{usable} && !$args->{nocache};
395 ### else, check if the hash key is defined already,
396 ### meaning $mod => 0,
397 ### indicating UNSUCCESSFUL prior attempt of usage
399 ### use qv(), as it will deal with developer release number
400 ### ie ones containing _ as well. This addresses bug report
401 ### #29348: Version compare logic doesn't handle alphas?
403 ### Update from JPeacock: apparently qv() and version->new
404 ### are different things, and we *must* use version->new
405 ### here, or things like #30056 might start happening
406 if ( !$args->{nocache}
407 && defined $CACHE->{$mod}->{usable}
408 && (version->new( $CACHE->{$mod}->{version}||0 )
409 >= version->new( $href->{$mod} ) )
411 $error = loc( q[Already tried to use '%1', which was unsuccessful], $mod);
415 my $mod_data = check_install(
417 version => $href->{$mod}
420 if( !$mod_data or !defined $mod_data->{file} ) {
421 $error = loc(q[Could not find or check module '%1'], $mod);
422 $CACHE->{$mod}->{usable} = 0;
427 $CACHE->{$mod}->{$_} = $mod_data->{$_}
428 } qw[version file uptodate];
433 for my $mod ( @load ) {
435 if ( $CACHE->{$mod}->{uptodate} ) {
439 ### in case anything goes wrong, log the error, the fact
440 ### we tried to use this module and return 0;
443 $CACHE->{$mod}->{usable} = 0;
446 $CACHE->{$mod}->{usable} = 1;
449 ### module not found in @INC, store the result in
450 ### $CACHE and return 0
453 $error = loc(q[Module '%1' is not uptodate!], $mod);
454 $CACHE->{$mod}->{usable} = 0;
461 if( defined $error ) {
463 Carp::carp( loc(q|%1 [THIS MAY BE A PROBLEM!]|,$error) ) if $args->{verbose};
472 =head2 @list = requires( MODULE );
474 C<requires> can tell you what other modules a particular module
475 requires. This is particularly useful when you're intending to write
476 a module for public release and are listing its prerequisites.
478 C<requires> takes but one argument: the name of a module.
479 It will then first check if it can actually load this module, and
480 return undef if it can't.
481 Otherwise, it will return a list of modules and pragmas that would
482 have been loaded on the module's behalf.
484 Note: The list C<require> returns has originated from your current
485 perl and your current install.
492 unless( check_install( module => $who ) ) {
493 warn loc(q[You do not have module '%1' installed], $who) if $VERBOSE;
497 my $lib = join " ", map { qq["-I$_"] } @INC;
498 my $cmd = qq["$^X" $lib -M$who -e"print(join(qq[\\n],keys(%INC)))"];
502 map { chomp; s|/|::|g; $_ }
511 =head1 Global Variables
513 The behaviour of Module::Load::Conditional can be altered by changing the
514 following global variables:
516 =head2 $Module::Load::Conditional::VERBOSE
518 This controls whether Module::Load::Conditional will issue warnings and
519 explanations as to why certain things may have failed. If you set it
520 to 0, Module::Load::Conditional will not output any warnings.
523 =head2 $Module::Load::Conditional::FIND_VERSION
525 This controls whether Module::Load::Conditional will try to parse
526 (and eval) the version from the module you're trying to load.
528 If you don't wish to do this, set this variable to C<false>. Understand
529 then that version comparisons are not possible, and Module::Load::Conditional
530 can not tell you what module version you have installed.
531 This may be desirable from a security or performance point of view.
532 Note that C<$FIND_VERSION> code runs safely under C<taint mode>.
536 =head2 $Module::Load::Conditional::CHECK_INC_HASH
538 This controls whether C<Module::Load::Conditional> checks your
539 C<%INC> hash to see if a module is available. By default, only
540 C<@INC> is scanned to see if a module is physically on your
541 filesystem, or available via an C<@INC-hook>. Setting this variable
542 to C<true> will trust any entries in C<%INC> and return them for
547 =head2 $Module::Load::Conditional::CACHE
549 This holds the cache of the C<can_load> function. If you explicitly
550 want to remove the current cache, you can set this variable to
553 =head2 $Module::Load::Conditional::ERROR
555 This holds a string of the last error that happened during a call to
556 C<can_load>. It is useful to inspect this when C<can_load> returns
559 =head2 $Module::Load::Conditional::DEPRECATED
561 This controls whether C<Module::Load::Conditional> checks if
562 a dual-life core module has been deprecated. If this is set to
563 true C<check_install> will return false to C<uptodate>, if
564 a dual-life module is found to be loaded from C<$Config{privlibexp}>
574 Please report bugs or other issues to E<lt>bug-module-load-conditional@rt.cpan.orgE<gt>.
578 This module by Jos Boumans E<lt>kane@cpan.orgE<gt>.
582 This library is free software; you may redistribute and/or modify it
583 under the same terms as Perl itself.