Announcing Module::UseFrom
So what do you do when you need to load a module from a string? Do you do eval "require $module"
? Well as many of you may have read, that is How (not) to Load a Module. This mechanism is unsafe in certain situations, but sadly there hasn’t been a good answer for it.
What do you do when you want to load a module only if it is installed, or only if it is of a certain version or higher (without die
ing). Of course there are eval
ways around that too, but could they be easier?
This post announces Module::UseFrom
, which lets you do all of these things. But it gets better! All of these actions are done using the much safer bareword form of use
, accomplishes this at compile time, and does it without any eval
s[1]!
It does all this using Devel::Declare
to inspect a package variable in your module and inject a bareword use
statement. This means that it avoid most (all?) of the problems Schwern’s post (above); if it fails to create the right statement, perl (yes lowercase) dies on the use Bareword::Module
statement.
Check it out, fork, comment etc. https://github.com/jberger/Module-UseFrom
Happy New Year everyone!
[1]: ok, there is a s///e
, but its for convenience, and its safe.
Joel asked for my commentary, so here it is.
Pro: Using
Devel::Declare
to get around the problems of loading a module dynamically is a very clever solution…Con: …but it severely restricts the utility of the module. It can only be used when you know what you’re loading at compile time.
Other: The basic
use_from
is fine, but extras are tacked on to avoid writinguse_from
more than once. They gum up the interface. They causeuse_from
to diverge from the knownuse
interface. More for the user to read and get confused about. More opportunities for bugs and security holes. I would simply remove them. The only actual extra functionality ischeck_installed
which should be its own function.use_if_installed
or something.In conclusion, if you happen to need to load modules dynamically and at compile time, this is the module for you.
@Schwern: Thank you for the comments! I guess I show my hand in that interface; I am most interested in loading Module::Build subclasses in a Build.PL file. You are probably right about simplifying the interface though.
It grew up this way, after getting the scalar type call working, I wanted to be able to inject imports and versioning too. I figured this kind of interface suggested a hash style call. Once I got that working there was no reason not to allow an array call because the hashkeys were basically already an array. Then once the idea for
check_installed
occurred to me, it was an easy tack-on. Of course this is exactly where a confusing interface can come from.Perhaps your suggestion is best, leave
use_from
as is implemented for the scalar type. What to do with ause_if_installed
will be a deeper question; probably should make that a scalar type too and make it parse in the version if given. That type will probably have to croak if it doesn’t see a;
on the same line. D::D is a beast.Thanks again!
If anyone is reading this and is now afraid to try for lack of interface stability: use the
use_from $scalar ...
type, that will not change.As I have been trying to come up with a cleaner interface, I can’t seem to come up with it. I probably need to sleep on it.