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 dieing). 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 evals[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.
As I delve into the deeper Perl magic I like to share what I can.
Joel asked for my commentary, so here it is.
Pro: Using
Devel::Declareto 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_fromis fine, but extras are tacked on to avoid writinguse_frommore than once. They gum up the interface. They causeuse_fromto diverge from the knownuseinterface. 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_installedwhich should be its own function.use_if_installedor 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_installedoccurred 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_fromas is implemented for the scalar type. What to do with ause_if_installedwill 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.