NAME
    Hook::Modular - Making pluggable applications easy

SYNOPSIS
    In "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 { ... }

    And this is "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 the "global" 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 of
            "PLUGIN_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. This 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 the "global" 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 to
        "My::Test::Plugin" and the config file specifies a plugin with the
        name "Some::Printer", we will try to load
        "My:::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()" and
        "rule_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.

BUGS AND LIMITATIONS
    No bugs have been reported.

    Please report any bugs or feature requests 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://search.cpan.org/dist/Hook-Modular/>.

AUTHORS
    Tatsuhiko Miyagawa "<miyagawa@bulknews.net>"

    Marcel Grünauer, "<marcel@cpan.org>"

COPYRIGHT AND LICENSE
    Copyright 2007-2009 by the authors.

    This library is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.

