use Config::XPath;Given a config file that perhaps looks like
use Module::PluginFinder;
my $conf = Config::XPath->new( filename => 'foomangler.conf' );
my $finder = Module::PluginFinder->new(
search_path => 'FooMangler::Plugin',
typefunc => 'TYPE',
);
my %plugins;
foreach my $plugin_conf ( $conf->get_sub_list( '/plugin' ) ) {
my $name = $plugin_conf->get_string( '@name' );
my $type = $plugin_conf->get_string( '@type' );
$plugins{$name} = $finder->construct( $type, $plugin_conf );
}
<foomangler>We can implement a plugin for this system quite simply, and have it be automatically discovered by the plugin system, instances created, and passed in its configuration from the config file:
<plugin type="hello" name="hello_world">
<message>Hello, world</message>
</plugin>
</foomangler>
package FooMangler::Plugin::Hello;
use constant TYPE => "hello";
sub new
{
my $class = shift;
my ( $config ) = @_;
my $message = $config->get_string( 'message' );
...
}
As well as providing one-shot reading support, it also has a subclass Config::XPath::Reloadable which allows for convenient reloading of config files. It itself keeps track of which XML nodes it has already seen, based on some defined key attribute, so it can determine additions and deletions. It will invoke callback functions when items are added or deleted, or their underlying config may have changed.
use Config::XPath::Reloadable;Now, whenever a SIGHUP signal is received, the config file is re-read. The configurations for all the current manglers are updated, new ones added, and old ones deleted.
my $conf = Config::XPath::Reloadable->new( filename => 'foomangler.conf' );
my $finder = Module::PluginFinder->new( ... );
$SIG{HUP} = sub { $conf->reload };
my %manglers;
$conf->associate_nodeset( '/mangler', '@name',
add => sub {
my ( $name, $mangler_conf ) = @_;
my $type = $mangler_conf->get_string( '@type' );
$manglers{$name} = $finder->construct( $type, $mangler_conf );
},
keep => sub {
my ( $name, $mangler_conf ) = @_;
$manglers{$name}->reconfigure( $mangler_conf );
},
remove => sub {
my ( $name ) = @_;
delete $manglers{$name};
},
);
I've just uploaded a new release, 0.16. This release finally gets rid of the awkward Error-based exceptions, instead using plain-old Carp-based string exceptions. This removes a dependency on the old, deprecated, and unsupported Error distribution.
I've also manually set the configure_requires element to set the required version of Module::Build down to 0.2808, which is what Perl 5.10.0 shipped with, rather than let it pick its own version, where it sets it to 0.36. Hopefully this should lead to no awkward "please upgrade Module::Build" on clean-slate installs. If this comes out OK I might start applying that by default across all my dists (where appropriate). It does seem a little awkward, but then I can't really think of a neater way for it to detect that - hard for it to know, for example, about random methods or functionality invoked during the Build.PL file itself, or bugs/features implicitly relied upon. Something to think about for next time, I feel...
No comments:
Post a Comment