NAME
Hook::Modular - making pluggable applications easy
SYNOPSIS
# some_config.yaml
global:
log:
level: error
cache:
base: /tmp/test-hook-modular
# plugin_namespace: My::Test::Plugin
plugins:
- module: Some::Printer
config:
indent: 4
indent_char: '*'
text: 'this is some printer'
# here is the plugin:
package My::Test::Plugin::Some::Printer;
use warnings;
use strict;
use base 'Hook::Modular::Plugin';
sub register {
my ($self, $context) = @_;
$context->register_hook($self,
'output.print' => $self->can('do_print'));
}
sub do_print { ... }
# some_app.pl
use base 'Hook::Modular';
use constant PLUGIN_NAMESPACE => 'My::Test::Plugin';
sub run {
my $self = shift;
$self->SUPER::run(@_);
...
$self->run_hook('output.print', ...);
...
}
main->bootstrap(config => $config_filename);
DESCRIPTION
Hook::Modular makes writing pluggable applications easy. Use a config file to specify which plugins you want and to pass options to those plugins. The program to support those plugin then subclasses Hook::Modular and bootstraps itself. This causes the plugins to be loaded and registered. This gives each plugin the chance to register callbacks for any or all hooks the program offers. The program then runs the hooks in the order it desires. Each time a hook is run, all the callbacks the plugins have registered with this particular hook are run in order.
Hook::Modular does more than just load and call plugins, however. It also supports the following concepts:
- Cache
-
Plugins can cache their settings. Cached items can also expire after a given time.
- Crypt
-
Hook::Lexwrap can go over your config file and encrypt any passwords it finds (as determined by the key
password
). It will then rewrite the config file and make a backup of the original file. Encrypting and rewriting is turned off by default, but subclasses can enable it, or you can enable it from a config file itself.At the moment, encrypting is rather basic: The passwords are only turned into base64.
- Rules
-
Hook::Modular supports rule-based dispatch of plugins.
METHODS
- new
-
my $obj = Hook::Modular->new(config => $config_file_name);
Creates a new object and initializes it. The arguments are passed as a named hash. Valid argument keys:
- config
-
Reads or sets the global configuration.
If the value is a simple string, it is interpreted as a filename. If the file is readable, it is loaded as YAML. If the filename is
-
, the configuration is read from STDIN.If the value is a scalar reference, the dereferenced value is assumed to be YAML and is loaded.
If the value is a hash reference, the configuration is cloned from that hash reference.
The constructor also sets the application-wide configuration, which can be accessed using
conf()
, to theglobal
part of the configuration data that has been passed to the constructor. This configuration is then augmented in various ways:- log level
-
my $level = $self->conf->{log}{level}
The log level is set to
debug
, if it hasn't been set by the configuration data already.In the config file, you can specify it this way:
global: log: level: info
- log encoding
-
my $encoding = $self->conf->{log}{encoding}
The log encoding is set to the current terminal's encoding, if it hasn't been set by the configuration data already.
In the config file, you can specify it this way:
global: log: level: info
- plugin_namespace
-
my $ns = $self->conf->{plugin_namespace};
The default plugin namespace is set to whatever the class defines as the
PLUGIN_NAMESPACE
constant, if the configuration data hasn't set it already. See the documentation ofPLUGIN_NAMESPACE
for details. - should_rewrite_config
-
my $should_rewrite_config = $self->conf->{should_rewrite_config};
If the configuration data hasn't set it already to either 0 or 1, config file rewriting is turned off. See the documentation of
SHOULD_REWRITE_CONFIG
for details. - rule_namespaces
-
If the config file specifies any rule namespaces, they are added to the default rule namespaces. See the documentation of
add_to_rule_namespaces()
for details.
- context, set_context
-
my $context = $self->context; $self->set_context($context);
Gets and sets (respectively) the global context. It is singular; each program has only one context. Thie can be used to communicate between the plugins.
- conf
-
my %conf = $self->conf; my $plugin_path = $self->conf->{plugin_path} || []; $self->conf->{log}{level} = 'debug';
Returns a hash that has the application-wide configuration. It is set during
new()
from theglobal
section of the configuration data and augmented with various other settings. - PLUGIN_NAMESPACE
-
package My::TestApp; use base 'Hook::Modular'; use constant PLUGIN_NAMESPACE => 'My::Test::Plugin';
A constant that specifies the namespace that is prepended to plugin names found in the configuration. Defaults to
Hook::Modular::Plugin
. Subclasses can and probably should override this value. For example, if the plugin namespace is set toMy::Test::Plugin
and the config file specifies a plugin with the nameSome::Printer
, we will try to loadMy:::Test::Plugin::Some::Printer
.In the config file, you can specify it this way:
global: plugin_namespace: My::Test::Plugin
- SHOULD_REWRITE_CONFIG
-
package My::TestApp; use base 'Hook::Modular'; use constant SHOULD_REWRITE_CONFIG => 1;
Hook::Modular can rewrite your config file, for example, to turn passwords into encrypted forms so they are not easily readable in the plain text. This behaviour is turned off by default, but the config file, or a subclass of Hook::Modular, can turn it on. In a config file, specify it this way:
In the config file, you can specify it this way:
global: should_rewrite_config: 1
- add_to_rule_namespace
-
$self->add_to_rule_namespaces( qw/Some::Rule::Namespace Other::Rule::Namespace/);
Hook::Modular supports multiple rule namespace, that is, package prefixes that are used when looking for rule classes. The reason to allow multiple rule namespace is that Hook::Modular has some rules, and your subclass might well define its own rules, so Hook::Modular needs to know which package it might find rules in.
There is only one list of rule namespace per program. To add to rule namespaces in your program, don't access
conf()
directly, but use the proper class methods to do so:add_to_rule_namespaces()
andrule_namespaces()
.You can add to rule namespaces using the config file like this:
global: rule_namespaces: - Some::Thing::Rule - Other::Thing::Rule
or, if you only want to add one rule namespace:
global: rule_namespaces: Some::Thing::Rule
- rule_namespaces
-
my @ns = $self->rule_namespaces;
Returns the list of rule namespaces. See the documentation of
add_to_rule_namespaces
for details.
TAGS
If you talk about this module in blogs, on del.icio.us or anywhere else, please use the hookmodular
tag.
BUGS AND LIMITATIONS
No bugs have been reported.
Please report any bugs or feature requests to bug-hook-modular@rt.cpan.org
, or through the web interface at http://rt.cpan.org.
INSTALLATION
See perlmodinstall for information and options on installing Perl modules.
AVAILABILITY
The latest version of this module is available from the Comprehensive Perl Archive Network (CPAN). Visit <http://www.perl.com/CPAN/> to find a CPAN site near you. Or see <http://www.perl.com/CPAN/authors/id/M/MA/MARCEL/>.
AUTHOR
Marcel Grünauer, <marcel@cpan.org>
The code is almost completely lifted from Plagger, so really Tatsuhiko Miyagawa <miyagawa@bulknews.net>
deserves all the credit.
COPYRIGHT AND LICENSE
Copyright 2007 by Marcel Grünauer
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.