Making a perl module optional?

Discussion in 'Perl Misc' started by Richard, Aug 23, 2005.

  1. Richard

    Richard Guest

    Hi there,

    Is there any way to make the requirement of a module optional? The
    reason I ask is that my application can show some additional
    functionality but only if a relativily unknown module is installed (and
    the many pre-requisits it has) too.

    As such, I don't want to prevent people who don't have this installed
    from using the application - albeit in its limited form.

    Is there any way to detect whether this module is installed and then,
    based on that, enable/disable certain parts of my perl application
    associated with it?

    Many thanks in advance,

    Richard.
     
    Richard, Aug 23, 2005
    #1
    1. Advertisements

  2. Richard

    Paul Lalli Guest

    Attempt to load the module within an eval{} block, and then check for
    errors (eval{} is Perl's way of doing a try/catch). If there's an
    error, set your global flag to a false value, otherwise set it to a
    true value.

    Depending on your needs, you may or may not want to wrap the whole
    thing in a BEGIN{} block:

    Example:
    #!/usr/bin/perl
    use strict;
    use warnings;

    BEGIN {
    eval {
    #separate out the two steps of 'use' - otherwise this
    #happens at compile time.
    require Foo;
    Foo->import();
    };
    if ([email protected]){ #check for an error in previous eval{}
    print "Foo not loaded; continuing without additional
    functionality\n";
    $main::use_foo = 0;
    } else {
    print "Foo loaded. Using Foo's functionality\n";
    $main::use_foo = 1;
    }
    }

    #main...

    our $use_foo;

    #some code...
    if ($use_foo){
    print "Here we'll do something with Foo\n";
    } else {
    print "Too bad you don't have Foo! This'd be really cool!\n";
    }
    #more code...

    __END__

    Hope this helps,
    Paul Lalli
     
    Paul Lalli, Aug 23, 2005
    #2
    1. Advertisements

  3. Richard

    Average_Joe Guest

    Lots of ways, but the general idea is to place it in an eval { .. }
    block.

    This can be trickier than it seems, because your application may
    or may not have logic surrounding the modules. A _lot_ of how you
    do it will depend on how your main program is designed.

    My personal favorite is to place the stuff in a package and then
    use the "driver/factory" approach:

    sub my_factory {
    my($file) = ... # Get $file/$package from some place, config, etc..
    my($package) = ... # Get $package from some place.

    # Could also use the wrapped eval { } block and test for failure.
    # Doesn't work if the underlying implementation changes, but that
    # may be OK.

    if($file){
    require($file);
    return($package->new());
    }else{
    # Something that handles "Can't do it" situations.
    return(My::Default::Implementation->new());
    }
    }

    Where My::Default::Implementation is just a package that says
    "I'm sorry, I can't do that" with it's methods. Of course, that
    only works with objects, require() doesn't call import for you.

    Could also return an empty list if not available, but, then your
    application has to test for that each time. :-/

    "My::Default::Implementation" could just have AUTOLOAD auto-generate methods
    that die with an error message (or reference, or however you want to do it,
    example: die "unsupported operation\n";

    $drv = my_factory(); # Get object that may do optional things, or, handle
    # cases where it can't do optional things.

    while($event_loop_if_you_have_one){
    eval {

    ... do stuff ...

    };
    if([email protected] eq "unsupported operation\n"){
    print "Sorry, no can do!\n";
    }else{
    die [email protected]; # Pass it up the chain.
    }
    }

    NOTE: eval using {} NOT "".

    Having optional modules can really burden the application, cluttering
    up the code with tons of "if($optional_is_supported) { .. }" chunks.

    Jamie
     
    Average_Joe, Sep 1, 2005
    #3
  4. Richard

    Anno Siegel Guest

    Detecting whether a module is installed is best done by trying to
    load it (this has been discussed in other followups).

    Here is a slightly different approach. If your module can optionally
    make use of some module Aux, require the user to "use Aux" before they
    load your module. Then in your module, test if $Aux::VERSION is defined
    and proceed accordingly. The "if" pragma can be useful here:

    use if defined $Aux::VERSION Aux => qw( ...);

    in case you need to import functions or otherwise activate the
    Aux->import method. See "perldoc if".

    That requires more action from the user than automatically loading the
    module if it is installed, but it makes the difference visible near the
    "use" statement.

    Anno
     
    Anno Siegel, Sep 1, 2005
    #4
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.