How can I dynamically include Perl modules without using eval?

前端 未结 6 1293
青春惊慌失措
青春惊慌失措 2020-11-29 03:13

I need to dynamically include a Perl module, but if possible would like to stay away from eval due to work coding standards. This works:

$module = \"My::modu         


        
相关标签:
6条回答
  • 2020-11-29 03:25

    Use require to load modules at runtime. It often a good idea to wrap this in a block (not string) eval in case the module can't be loaded.

    eval {
        require My::Module;
        My::Module->import();
        1;
    } or do {
       my $error = $@;
       # Module load failed. You could recover, try loading
       # an alternate module, die with $error...
       # whatever's appropriate
    };
    

    The reason for the eval {...} or do {...} syntax and making a copy of $@ is because $@ is a global variable that can be set by many different things. You want to grab the value as atomically as possible to avoid a race condition where something else has set it to a different value.

    If you don't know the name of the module until runtime you'll have to do the translation between module name (My::Module) and file name (My/Module.pm) manually:

    my $module = 'My::Module';
    
    eval {
        (my $file = $module) =~ s|::|/|g;
        require $file . '.pm';
        $module->import();
        1;
    } or do {
        my $error = $@;
        # ...
    };
    
    0 讨论(0)
  • 2020-11-29 03:27

    How about using the core module Module::Load

    With your example:

    use Module::Load;
    my $module = "My::module";
    load $module;
    

    "Module::Load - runtime require of both modules and files"

    "load eliminates the need to know whether you are trying to require either a file or a module."

    If it fails it will die with something of the like "Can't locate xxx in @INC (@INC contains: ...".

    0 讨论(0)
  • 2020-11-29 03:27

    i like doing things like..

    require Win32::Console::ANSI if ( $^O eq "MSWin32" );

    0 讨论(0)
  • Class::MOP on CPAN has a load_class method for this: http://metacpan.org/pod/Class::MOP

    0 讨论(0)
  • 2020-11-29 03:39

    No, it's not possible to without eval, as require() needs the bareword module name, as described at perldoc -f require. However, it's not an evil use of eval, as it doesn't allow injection of arbitrary code (assuming you have control over the contents of the file you are requireing, of course).

    EDIT: Code amended below, but I'm leaving the first version up for completeness.

    I use I used to use this little sugar module to do dynamic loads at runtime:

    package MyApp::Util::RequireClass;
    
    use strict;
    use warnings;
    
    use Exporter 'import'; # gives you Exporter's import() method directly
    our @EXPORT_OK = qw(requireClass);
    
    # Usage: requireClass(moduleName);
    # does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
    sub requireClass
    {
        my ($class) = @_;
        eval "require $class" or do { die "Ack, can't load $class: $@" };
    }
    
    1;
    

    PS. I'm staring at this definition (I wrote it quite a while ago) and I'm pondering adding this: $class->export_to_level(1, undef, @imports);... it should work, but is not tested.

    EDIT: version 2 now, much nicer without an eval (thanks ysth): :)

    package MyApp::Util::RequireClass;
    
    use strict;
    use warnings;
    
    use Exporter 'import'; # gives you Exporter's import() method directly
    our @EXPORT_OK = qw(requireClass);
    
    # Usage: requireClass(moduleName);
    # does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
    sub requireClass
    {
        my ($class) = @_;
    
        (my $file = $class) =~ s|::|/|g;
        $file .= '.pm';
        require $file;  # will die if there was an error
    }
    
    1;
    
    0 讨论(0)
  • 2020-11-29 03:45

    Well, there's always require as in

    require 'My/Module.pm';
    My::Module->import();
    

    Note that you lose whatever effects you may have gotten from the import being called at compile time instead of runtime.

    Edit: The tradeoffs between this and the eval way are: eval lets you use the normal module syntax and gives you a more explicit error if the module name is invalid (as opposed to merely not found). OTOH, the eval way is (potentially) more subject to arbitrary code injection.

    0 讨论(0)
提交回复
热议问题