1 package Module::Load::Conditional;
6 use Params::Check qw[check];
7 use Locale::Maketext::Simple Style => 'gettext';
14 use constant ON_VMS => $^O eq 'VMS';
17 use vars qw[ $VERSION @ISA $VERBOSE $CACHE @EXPORT_OK $DEPRECATED
18 $FIND_VERSION $ERROR $CHECK_INC_HASH];
26 @EXPORT_OK = qw[check_install can_load requires];
33 Module::Load::Conditional - Looking up module information / loading at runtime
37 use Module::Load::Conditional qw[can_load check_install requires];
43 'Test::More' => undef,
46 print can_load( modules => $use_list )
47 ? 'all modules loaded successfully'
48 : 'failed to load required modules';
51 my $rv = check_install( module => 'LWP', version => 5.60 )
52 or print 'LWP is not installed!';
54 print 'LWP up to date' if $rv->{uptodate};
55 print "LWP version is $rv->{version}\n";
56 print "LWP is installed as file $rv->{file}\n";
59 print "LWP requires the following modules to be installed:\n";
60 print join "\n", requires('LWP');
62 ### allow M::L::C to peek in your %INC rather than just
64 $Module::Load::Conditional::CHECK_INC_HASH = 1;
66 ### reset the 'can_load' cache
67 undef $Module::Load::Conditional::CACHE;
69 ### don't have Module::Load::Conditional issue warnings --
71 $Module::Load::Conditional::VERBOSE = 0;
73 ### The last error that happened during a call to 'can_load'
74 my $err = $Module::Load::Conditional::ERROR;
79 Module::Load::Conditional provides simple ways to query and possibly load any of
80 the modules you have installed on your system during runtime.
82 It is able to load multiple modules at once or none at all if one of
83 them was not able to load. It also takes care of any error checking
88 =head2 $href = check_install( module => NAME [, version => VERSION, verbose => BOOL ] );
90 C<check_install> allows you to verify if a certain module is installed
91 or not. You may call it with the following arguments:
97 The name of the module you wish to verify -- this is a required key
101 The version this module needs to be -- this is optional
105 Whether or not to be verbose about what it is doing -- it will default
106 to $Module::Load::Conditional::VERBOSE
110 It will return undef if it was not able to find where the module was
111 installed, or a hash reference with the following keys if it was able
118 Full path to the file that contains the module
122 Directory, or more exact the C<@INC> entry, where the module was
127 The version number of the installed module - this will be C<undef> if
128 the module had no (or unparsable) version number, or if the variable
129 C<$Module::Load::Conditional::FIND_VERSION> was set to true.
130 (See the C<GLOBAL VARIABLES> section below for details)
134 A boolean value indicating whether or not the module was found to be
135 at least the version you specified. If you did not specify a version,
136 uptodate will always be true if the module was found.
137 If no parsable version was found in the module, uptodate will also be
138 true, since C<check_install> had no way to verify clearly.
140 See also C<$Module::Load::Conditional::DEPRECATED>, which affects
141 the outcome of this value.
147 ### this checks if a certain module is installed already ###
148 ### if it returns true, the module in question is already installed
149 ### or we found the file, but couldn't open it, OR there was no version
150 ### to be found in the module
151 ### it will return 0 if the version in the module is LOWER then the one
152 ### we are looking for, or if we couldn't find the desired module to begin with
153 ### if the installed version is higher or equal to the one we want, it will return
154 ### a hashref with he module name and version in it.. so 'true' as well.
159 version => { default => '0.0' },
160 module => { required => 1 },
161 verbose => { default => $VERBOSE },
165 unless( $args = check( $tmpl, \%hash, $VERBOSE ) ) {
166 warn loc( q[A problem occurred checking arguments] ) if $VERBOSE;
170 my $file = File::Spec->catfile( split /::/, $args->{module} ) . '.pm';
171 my $file_inc = File::Spec::Unix->catfile(
172 split /::/, $args->{module}
175 ### where we store the return value ###
184 ### check the inc hash if we're allowed to
185 if( $CHECK_INC_HASH ) {
186 $filename = $href->{'file'} =
187 $INC{ $file_inc } if defined $INC{ $file_inc };
189 ### find the version by inspecting the package
190 if( defined $filename && $FIND_VERSION ) {
192 $href->{version} = ${ "$args->{module}"."::VERSION" };
196 ### we didnt find the filename yet by looking in %INC,
198 unless( $filename ) {
200 DIR: for my $dir ( @INC ) {
205 ### @INC hook -- we invoke it and get the filehandle back
206 ### this is actually documented behaviour as of 5.8 ;)
208 my $existed_in_inc = $INC{$file_inc};
210 if (UNIVERSAL::isa($dir, 'CODE')) {
211 ($fh) = $dir->($dir, $file);
213 } elsif (UNIVERSAL::isa($dir, 'ARRAY')) {
214 ($fh) = $dir->[0]->($dir, $file, @{$dir}{1..$#{$dir}})
216 } elsif (UNIVERSAL::can($dir, 'INC')) {
217 ($fh) = $dir->INC($file);
220 if (!UNIVERSAL::isa($fh, 'GLOB')) {
221 warn loc(q[Cannot open file '%1': %2], $file, $!)
226 $filename = $INC{$file_inc} || $file;
228 delete $INC{$file_inc} if not $existed_in_inc;
231 $filename = File::Spec->catfile($dir, $file);
232 next unless -e $filename;
234 $fh = new FileHandle;
235 if (!$fh->open($filename)) {
236 warn loc(q[Cannot open file '%1': %2], $file, $!)
242 ### store the directory we found the file in
245 ### files need to be in unix format under vms,
246 ### or they might be loaded twice
247 $href->{file} = ON_VMS
248 ? VMS::Filespec::unixify( $filename )
251 ### user wants us to find the version from files
252 if( $FIND_VERSION ) {
256 while ( $line = <$fh> ) {
258 ### #24062: "Problem with CPANPLUS 0.076 misidentifying
259 ### versions after installing Text::NSP 1.03" where a
260 ### VERSION mentioned in the POD was found before
261 ### the real $VERSION declaration.
262 if( $line =~ /^=(.{0,3})/ ) {
263 $in_pod = $1 ne 'cut';
267 ### skip lines which doesn't contain VERSION
268 next unless $line =~ /VERSION/;
270 ### try to find a version declaration in this string.
271 my $ver = __PACKAGE__->_parse_version( $line );
274 $href->{version} = $ver;
283 ### if we couldn't find the file, return undef ###
284 return unless defined $href->{file};
286 ### only complain if we're expected to find a version higher than 0.0 anyway
287 if( $FIND_VERSION and not defined $href->{version} ) {
288 { ### don't warn about the 'not numeric' stuff ###
291 ### if we got here, we didn't find the version
292 warn loc(q[Could not check version on '%1'], $args->{module} )
293 if $args->{verbose} and $args->{version} > 0;
295 $href->{uptodate} = 1;
298 ### don't warn about the 'not numeric' stuff ###
301 ### use qv(), as it will deal with developer release number
302 ### ie ones containing _ as well. This addresses bug report
303 ### #29348: Version compare logic doesn't handle alphas?
305 ### Update from JPeacock: apparently qv() and version->new
306 ### are different things, and we *must* use version->new
307 ### here, or things like #30056 might start happening
309 ### We have to wrap this in an eval as version-0.82 raises
310 ### exceptions and not warnings now *sigh*
315 version->new( $args->{version} ) <= version->new( $href->{version} )
322 if ( $DEPRECATED and version->new($]) >= version->new('5.011') ) {
323 require Module::CoreList;
326 $href->{uptodate} = 0 if
327 exists $Module::CoreList::version{ 0+$] }{ $args->{module} } and
328 Module::CoreList::is_deprecated( $args->{module} ) and
329 $Config::Config{privlibexp} eq $href->{dir};
337 my $str = shift or return;
338 my $verbose = shift || 0;
340 ### skip commented out lines, they won't eval to anything.
341 return if $str =~ /^\s*#/;
343 ### the following regexp & eval statement comes from the
344 ### ExtUtils::MakeMaker source (EU::MM_Unix->parse_version)
345 ### Following #18892, which tells us the original
346 ### regex breaks under -T, we must modify it so
347 ### it captures the entire expression, and eval /that/
348 ### rather than $_, which is insecure.
349 my $taint_safe_str = do { $str =~ /(^.*$)/sm; $1 };
351 if( $str =~ /(?<!\\)([\$*])(([\w\:\']*)\bVERSION)\b.*\=/ ) {
353 print "Evaluating: $str\n" if $verbose;
355 ### this creates a string to be eval'd, like:
356 # package Module::Load::Conditional::_version;
360 # $VERSION=undef; do {
361 # use version; $VERSION = qv('0.0.3');
365 package Module::Load::Conditional::_version;
374 print "Evaltext: $eval\n" if $verbose;
382 my $rv = defined $result ? $result : '0.0';
384 print( $@ ? "Error: $@\n" : "Result: $rv\n" ) if $verbose;
389 ### unable to find a version in this string
393 =head2 $bool = can_load( modules => { NAME => VERSION [,NAME => VERSION] }, [verbose => BOOL, nocache => BOOL] )
395 C<can_load> will take a list of modules, optionally with version
396 numbers and determine if it is able to load them. If it can load *ALL*
397 of them, it will. If one or more are unloadable, none will be loaded.
399 This is particularly useful if you have More Than One Way (tm) to
400 solve a problem in a program, and only wish to continue down a path
401 if all modules could be loaded, and not load them if they couldn't.
403 This function uses the C<load> function from Module::Load under the
406 C<can_load> takes the following arguments:
412 This is a hashref of module/version pairs. The version indicates the
413 minimum version to load. If no version is provided, any version is
414 assumed to be good enough.
418 This controls whether warnings should be printed if a module failed
420 The default is to use the value of $Module::Load::Conditional::VERBOSE.
424 C<can_load> keeps its results in a cache, so it will not load the
425 same module twice, nor will it attempt to load a module that has
426 already failed to load before. By default, C<can_load> will check its
427 cache, but you can override that by setting C<nocache> to true.
435 modules => { default => {}, strict_type => 1 },
436 verbose => { default => $VERBOSE },
437 nocache => { default => 0 },
442 unless( $args = check( $tmpl, \%hash, $VERBOSE ) ) {
443 $ERROR = loc(q[Problem validating arguments!]);
444 warn $ERROR if $VERBOSE;
448 ### layout of $CACHE:
453 ### file => /path/to/file,
457 $CACHE ||= {}; # in case it was undef'd
461 my $href = $args->{modules};
464 for my $mod ( keys %$href ) {
466 next if $CACHE->{$mod}->{usable} && !$args->{nocache};
468 ### else, check if the hash key is defined already,
469 ### meaning $mod => 0,
470 ### indicating UNSUCCESSFUL prior attempt of usage
472 ### use qv(), as it will deal with developer release number
473 ### ie ones containing _ as well. This addresses bug report
474 ### #29348: Version compare logic doesn't handle alphas?
476 ### Update from JPeacock: apparently qv() and version->new
477 ### are different things, and we *must* use version->new
478 ### here, or things like #30056 might start happening
479 if ( !$args->{nocache}
480 && defined $CACHE->{$mod}->{usable}
481 && (version->new( $CACHE->{$mod}->{version}||0 )
482 >= version->new( $href->{$mod} ) )
484 $error = loc( q[Already tried to use '%1', which was unsuccessful], $mod);
488 my $mod_data = check_install(
490 version => $href->{$mod}
493 if( !$mod_data or !defined $mod_data->{file} ) {
494 $error = loc(q[Could not find or check module '%1'], $mod);
495 $CACHE->{$mod}->{usable} = 0;
500 $CACHE->{$mod}->{$_} = $mod_data->{$_}
501 } qw[version file uptodate];
506 for my $mod ( @load ) {
508 if ( $CACHE->{$mod}->{uptodate} ) {
512 ### in case anything goes wrong, log the error, the fact
513 ### we tried to use this module and return 0;
516 $CACHE->{$mod}->{usable} = 0;
519 $CACHE->{$mod}->{usable} = 1;
522 ### module not found in @INC, store the result in
523 ### $CACHE and return 0
526 $error = loc(q[Module '%1' is not uptodate!], $mod);
527 $CACHE->{$mod}->{usable} = 0;
534 if( defined $error ) {
536 Carp::carp( loc(q|%1 [THIS MAY BE A PROBLEM!]|,$error) ) if $args->{verbose};
545 =head2 @list = requires( MODULE );
547 C<requires> can tell you what other modules a particular module
548 requires. This is particularly useful when you're intending to write
549 a module for public release and are listing its prerequisites.
551 C<requires> takes but one argument: the name of a module.
552 It will then first check if it can actually load this module, and
553 return undef if it can't.
554 Otherwise, it will return a list of modules and pragmas that would
555 have been loaded on the module's behalf.
557 Note: The list C<require> returns has originated from your current
558 perl and your current install.
565 unless( check_install( module => $who ) ) {
566 warn loc(q[You do not have module '%1' installed], $who) if $VERBOSE;
570 my $lib = join " ", map { qq["-I$_"] } @INC;
571 my $cmd = qq["$^X" $lib -M$who -e"print(join(qq[\\n],keys(%INC)))"];
575 map { chomp; s|/|::|g; $_ }
584 =head1 Global Variables
586 The behaviour of Module::Load::Conditional can be altered by changing the
587 following global variables:
589 =head2 $Module::Load::Conditional::VERBOSE
591 This controls whether Module::Load::Conditional will issue warnings and
592 explanations as to why certain things may have failed. If you set it
593 to 0, Module::Load::Conditional will not output any warnings.
596 =head2 $Module::Load::Conditional::FIND_VERSION
598 This controls whether Module::Load::Conditional will try to parse
599 (and eval) the version from the module you're trying to load.
601 If you don't wish to do this, set this variable to C<false>. Understand
602 then that version comparisons are not possible, and Module::Load::Conditional
603 can not tell you what module version you have installed.
604 This may be desirable from a security or performance point of view.
605 Note that C<$FIND_VERSION> code runs safely under C<taint mode>.
609 =head2 $Module::Load::Conditional::CHECK_INC_HASH
611 This controls whether C<Module::Load::Conditional> checks your
612 C<%INC> hash to see if a module is available. By default, only
613 C<@INC> is scanned to see if a module is physically on your
614 filesystem, or available via an C<@INC-hook>. Setting this variable
615 to C<true> will trust any entries in C<%INC> and return them for
620 =head2 $Module::Load::Conditional::CACHE
622 This holds the cache of the C<can_load> function. If you explicitly
623 want to remove the current cache, you can set this variable to
626 =head2 $Module::Load::Conditional::ERROR
628 This holds a string of the last error that happened during a call to
629 C<can_load>. It is useful to inspect this when C<can_load> returns
632 =head2 $Module::Load::Conditional::DEPRECATED
634 This controls whether C<Module::Load::Conditional> checks if
635 a dual-life core module has been deprecated. If this is set to
636 true C<check_install> will return false to C<uptodate>, if
637 a dual-life module is found to be loaded from C<$Config{privlibexp}>
647 Please report bugs or other issues to E<lt>bug-module-load-conditional@rt.cpan.orgE<gt>.
651 This module by Jos Boumans E<lt>kane@cpan.orgE<gt>.
655 This library is free software; you may redistribute and/or modify it
656 under the same terms as Perl itself.