This is my general approach when I need to do something similar, in this case, a poor man's Module::Pluggable system:
# NOTE! This is just a snippet from a larger work shown only to illust
+rate the principle
use strict;
use warnings
use Cwd ();
use Try::Tiny;
# used to find the location of THIS module. assumes that all plug-ins
# will be under a directory named after this module (without the '.pm'
+)
sub _basename_dir {
my $class = shift;
# In this case, we want to always use THIS package's name, not a s
+ub-class
my $package = __PACKAGE__;
$package =~ s/::/\//g;
my $packpath = $INC{ join( '.', $package, 'pm' ) };
$packpath =~ s/\.pm$//;
my $realpath = Cwd::realpath($packpath);
return $realpath;
}
# be sure to get the method in THIS package, not a sub-class
my $basedir = __PACKAGE__->_basename_dir();
my $pdir = "$basedir/Plugin";
opendir( my $dh, $pdir)or die "Can not open $pdir";
my @plugins = grep { /\.pm$/ && -f "$basedir/Plugin/$_" } readdir($dh)
+;
closedir( $dh ) or die "Can not close $pdir";
for my $plugin ( @plugins ) {
my $ppkg = try {
my $package = __PACKAGE__;
# gotta change from '::' to '/' so require is happy.
$package =~ s/::/\//g;
my $ppath = join( '/', $package, 'Plugin', $plugin);
require $ppath;
# and now we change back to normal '::' without the .pm to use
+ as a class name.
$plugin =~ s{(?:\.pm)$}{};
my $pname = join( '::', __PACKAGE__, 'Plugin', $plugin );
return ($pname->isa( __PACKAGE__ ) && $pname->_enabled) ? $pna
+me : undef ;
}
catch {
warn "Invalid plugin: $plugin\n$_\n";
return;
} or next;
$ppkg->register();
}
There are probably better or cleaner ways to do this (this is Perl, after all) but this has been a very stable approach for me.
It helps to remember that the primary goal is to drain the swamp even when you are hip-deep in alligators.
|