Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

eval "require $class" seems wrong

by rvosa (Curate)
on Aug 22, 2007 at 17:34 UTC ( #634438=perlquestion: print w/ replies, xml ) Need Help??
rvosa has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,

there are some situations where I need to use/require a class from a variable (say $class). The way I do that is by:
eval "require $class"; if ( $@ ) { die "Can't load $class: $@"; } my $obj = $class->new;
...or something to that effect, i.e. by using a string eval. This feels wrong (perlcritic complains about it also). What's the right way?

Thanks!

Comment on eval "require $class" seems wrong
Download Code
Re: eval "require $class" seems wrong
by jZed (Prior) on Aug 22, 2007 at 17:37 UTC
    eval { require $class }; :-)

    update:

    eval { require "$class.pm" }; :-)
      That's not the same thing! Compare:
      perl -Mstrict -e 'my $c="CGI";eval "require $c";die $@ if $@' perl -Mstrict -e 'my $c="CGI";eval {require $c};die $@ if $@'
      Ah, the update works. I'd ++ that if I had votes left for today :)

        Then you are violating a different "best practice": Modules should always have a "::" in their name.

        - tye        

Re: eval "require $class" seems wrong
by lima1 (Curate) on Aug 22, 2007 at 17:38 UTC
      It looks like what UNIVERSAL::require does is: turn $class name (e.g. Some::Class) into a path (Some/Class.pm), then do eval qq{require $path}, which amounts to the same thing - a string eval - but hidden in a dependency. Okay, it checks %INC first to see if it's already been loaded, but that's about it.
        Sure, you need an eval here to check whether the module was found and successfully loaded. You need the eval in the first case to interpolate the module name and turn it into a bareword, or not?

        If you change "::" to "/" and append ".pm", then you don't need a string eval, you can just do require $class. I wouldn't even do eval { require $class } (non-string eval) unless I was wanting to work around the module not being found. But if you do want to eval, then the best choice is:

        ( my $file= $class ) =~ s-::|'-/-g; if( ! eval { require "$file.pm"; 1 } ) { # work-around the failure here }

        But I don't find the argument against string eval compelling enough to have much of a strong preference between that and the below string eval unless there is risk that $class might contain mischevious data:

        if( ! eval "require $class; 1" ) { # work-around the failure here }

        If you don't want to work-around a failure (and trust $class), then the choices are:

        eval "require $class; 1" or die $@;

        and

        ( my $file= $class ) =~ s-::|'-/-g; require "$file.pm";

        And I'd never use UNIVERSAL::require, since I consider poluting such a very global namespace to be way too much sin for the sake of saving one line of code.

        - tye        

        It uses eval EXPR for #line to work. It has nothing to do with require. (eval BLOCK would suffice if you wanted to catch exceptions.)

        The following will work (even if your platform doesn't use / as the path seperator):

        $class = 'HTTP/Request.pm'; require $class;

        However, transforming the class name into a path is really no better.

Re: eval "require $class" seems wrong
by ikegami (Pope) on Aug 22, 2007 at 17:48 UTC
      That also does a string eval, actually. See the _require sub in Module/Pluggable/Object.pm. Maybe I'm just barking up the wrong tree - I figured that something that's not uncommon (requiring a class at runtime, from a variable) could be done in a "best practices" sort of way. Apparently not. This seems strangely un-TIMTOWDI.

        I was kinda suggesting the best practice was to avoid requireing dynamic class names completely, and address the problem at a higher level.

        To answer your question directly, one can require either a class supplied as a bareword or a path. There isn't a way to require a class supplied in a scalar. In order to load a dynamically constructed class name, some use eval EXPR to do the former (e.g. Module::Pluggable), and some transform the class name into a path and use the latter (e.g. if). I have no idea why one cannot do require $class;.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://634438]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (8)
As of 2014-07-24 07:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (158 votes), past polls