Hooking into @INC
2014-06-05
In UAV::Pilot, there’s a shell called uav
that’s meant to be an easy way to mess around. It takes arbitrary Perl commands and runs them through eval()
. By loading up libraries into its context namespace, we can provide commands for all your basic UAV needs.
The old way of loading these libraries was to write them as a normal module, except without a package
statement at the top. When you loaded a library, UAV::Pilot::Command
would go digging around in the distro’s share dir. Once found, it slurps in the file, adds a package
for the namespace we want, and hands it to eval()
.
This worked OK, but it had the downside that for development, you couldn’t make in-place fixes to the library. File::ShareDir
gives you back the path to the distro’s system share directory, so you had to install the development distribution first and then find out if your fixes worked.
Then, I saw this tidbit in the perldelta for 5.20:
“Since Perl v5.10, it has been possible for subroutines in @INC to return a reference to a scalar holding initial source code to prepend to the file. This is now documented.”
Specifically, it’s documented in perlfunc under the require
entry. But what I really wanted was the method of sticking a subroutine in @INC.
When you do this, the subroutine is passed a reference to itself, and a path to the file. It should return a list of up to four things:
- Reference to a scalar, which is text that will be prepended to the module
- Filehandle to read from
- Subref, which if there is no filehandle above, will be called in a loop to get the module text until it returns 0
- Subroutine state var
For my purposes, I only needed to return the first two.
This means the Commands modules can be in the regular module paths (though still without a package
statement). This is was implemented in UAV::Pilot v1.0_0 trial release, and UAV::Pilot::ARDrone has been ported to the new way, too. WumpusRover should be forthcoming.
I’m letting the CPAN smoke testers go over the trial release before I put the big official v1.0 on the module, but we’re looking good so far.