How can I require an optional Perl module if installed?

PerlModuleRequire

Perl Problem Overview


I have Perl code which relies on Term::ReadKey to get the terminal width. My installation is missing this module, so I want to provide a default if the module isn't present rather than throw an exception.

How can I conditionally use an optional module, without knowing ahead of time whether it is available.

# but only if the module is installed and exists
use Term::ReadKey;
...

How can I accomplish this?

Perl Solutions


Solution 1 - Perl

Here's a bare-bones solution that does not require another module:

my $rc = eval
{
  require Term::ReadKey;
  Term::ReadKey->import();
  1;
};

if($rc)
{
  # Term::ReadKey loaded and imported successfully
  ...
}

Note that all the answers below (I hope they're below this one! :-) that use eval { use SomeModule } are wrong because use statements are evaluated at compile time, regardless of where in the code they appear. So if SomeModule is not available, the script will die immediately upon compiling.

(A string eval of a use statement will also work (eval 'use SomeModule';), but there's no sense parsing and compiling new code at runtime when the require/import pair does the same thing, and is syntax-checked at compile time to boot.)

Finally, note that my use of eval { ... } and $@ here is succinct for the purpose of this example. In real code, you should use something like http://search.cpan.org/dist/Try-Tiny/">Try::Tiny</a>;, or at least http://search.cpan.org/dist/Try-Tiny/lib/Try/Tiny.pm#BACKGROUND">be aware of the issues it addresses.

Solution 2 - Perl

Check out the CPAN module Module::Load::Conditional. It will do what you want.

Solution 3 - Perl

The classic answer (dating back to Perl 4, at least, long before there was a 'use') was to 'require()' a module. This is executed as the script is run, rather than when compiled, and you can test for success or failure and react appropriately.

Solution 4 - Perl

And if you require a specific version of the module:

my $GOT_READKEY;
BEGIN {
eval {
require Term::ReadKey;
Term::ReadKey->import();
$GOT_READKEY = 1 if $Term::ReadKey::VERSION >= 2.30;
};
}



elsewhere in the code



if ($GOT_READKEY) {
# ...
}

if ($GOT_READKEY) { # ... }

Solution 5 - Perl

if  (eval {require Term::ReadKey;1;} ne 1) {
# if module can't load
} else {
Term::ReadKey->import();
}

or

if  (eval {require Term::ReadKey;1;}) {
#module loaded
Term::ReadKey->import();
}

Note: the 1; only executes if require Term::... loaded properly.

Solution 6 - Perl

use Module::Load::Conditional qw(check_install);

use if check_install(module => 'Clipboard') != undef, 'Clipboard'; # class methods: paste, copy

using if pragma and Module::Load::Conditional core module.

check_install returns hashref or undef.


this module is also mentioned in the see also section of the pragma's documentation:

> Module::Load::Conditional provides a number of functions you can use to query what modules are available, and then load one or more of them at runtime.

Solution 7 - Perl

This is an effective idiom for loading an optional module (so long as you're not using it in a code base with sigdie handler),

use constant HAS_MODULE => defined eval { require Module };

This will require the module if available, and store the status in a constant.

You can use this like,

use constant HAS_READLINE => defined eval { require Term::ReadKey };

my $width = 80;
if ( HAS_READLINE ) {
  $width = # ... code, override default.
}

Note, if you need to import it and bring in the symbols you can easily do that too. You can follow it up.

use constant HAS_READLINE => defined eval { require Term::ReadKey };
Term::ReadKey->import if HAS_READLINE;

This method uses constants. This has the advantage that if you don't have this module the dead code paths are purged from the optree.

Solution 8 - Perl

I think it doesn't work when using variables. Please check this link which explains how it can be used with variable

$class = 'Foo::Bar';
        require $class;       # $class is not a bareword
    #or
        require "Foo::Bar";   # not a bareword because of the ""

The require function will look for the "Foo::Bar" file in the @INC array and will complain about not finding "Foo::Bar" there. In this case you can do:

 eval "require $class";

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondlamblinView Question on Stackoverflow
Solution 1 - PerlJohn SiracusaView Answer on Stackoverflow
Solution 2 - Perlm0j0View Answer on Stackoverflow
Solution 3 - PerlJonathan LefflerView Answer on Stackoverflow
Solution 4 - PerlHinrikView Answer on Stackoverflow
Solution 5 - PerlShqTthView Answer on Stackoverflow
Solution 6 - PerlElvinView Answer on Stackoverflow
Solution 7 - PerlEvan CarrollView Answer on Stackoverflow
Solution 8 - PerlUtkarsh KumarView Answer on Stackoverflow