NAME
    Plugin::Tiny - A tiny plugin system for perl

VERSION
    version 0.008

SYNOPSIS
      #a complete 'Hello World' plugin
      package My::Plugin; 
      use Moose; #optional; required is an object with new as constructor
    
      sub do_something { print "Hello World @_\n" }
    
      1;

      #in your core
      use Plugin::Tiny;           
      my $ps=Plugin::Tiny->new(); #plugin system
  
      #load My::Plugin: require, import, return My::Plugin->new(@_)
      my $plugin=$ps->register(plugin=>'My::Plugin');

      #elsewhere in core: execute your plugin's methods 
      my $plugin=$ps->get_plugin ($phase); 
      $plugin->do_something(@args);

DESCRIPTION
    Plugin::Tiny is minimalistic plugin system for perl. Each plugin is
    associated with a keyword (referred to as phase). A limitation of
    Plugin::Tiny is that each phase can have only one plugin.

ATTRIBUTES
  debug
    Optional. Expects a boolean. Prints additional info to STDOUT.

  prefix
    Optional. You can have the prefix added to all plugin classes you
    register so save some typing and force plugins in your namespace:

      #without prefix  
      my $ps=Plugin::Tiny->new  
      $ps->register(plugin='Your::App::Plugin::Example1');
      $ps->register(plugin='Your::App::Plugin::Example2');

      #with prefix  
      my $ps=Plugin::Tiny->new (  prefix=>'Your::App::Plugin::' );  
      $ps->register(plugin='Example1');
      $ps->register(plugin='Example2');

  role
    Optional. One or more roles that all plugins have to be able to do. Can
    be overwritten in "register".

        #either as ArrayRef 
        role=>['Role::One', Role::Two]
        #or a scalar
        role=>'Role::One'

METHODS
  register
    Registers a plugin, i.e. loads it and makes a new plugin object. Needs a
    plugin package name (plugin). Returns the newly created plugin object on
    success. Confesses on error. Remaining arguments are passed down to the
    plugin constructor:

        $obj=$ps->register(
            plugin=>$plugin_class,   #required
            args=>$more_args,        #optional
        );
        #Plugin::Tiny return result of
        #$plugin_class->new (args=>$args);

    N.B. A side-effect of these arguments is that your plugin cannot use
    'phase', 'plugin', 'role', 'force' as named arguments.

    plugin
        The package name of the plugin. Required. Internally, the value of
        "prefix" is prepended to plugin, if set.

    phase
        A phase asociated with the plugin. Optional. If not specified,
        Plugin::Tiny uses "default_phase" to determine the phase.

    role
        One or more roles that the plugin has to appply. Optional. Specify
        role=>undef to unset global roles.

            role=>'Single::Role' #or
            role=>['Role::One','Role:Two']
            role=>undef #unset global roles

        Currently, you can't mix global roles (defined via new) with local
        roles (defined via register).

    force
        Force re-registration of a previously used phase. Optional.

        Plugin::Tiny confesses if you try to register a phase that has
        previously been assigned. To overwrite this message make force true.

        With force both plugins will be loaded (required, imported) and both
        return new objects for their respective plugin classes, but after
        the second plugin is made, the first one cannot be accessed anymore
        through get_plugin.

  register_bundle
    Registers a bundle of plugins in no particular order. A bundle is just a
    hashRef with info needed to issue a series of register calls (see
    "register").

    Confesses if a plugin cannot be registered. Otherwise returns $bundle or
    undef.

      sub bundle{
        return {
          'Store::One' => {   
              phase  => 'Store',
              role   => undef,
              dbfile => $self->core->config->{main}{dbfile},
            },
           'Scan::Monitor'=> {   
              core   => $self->core
            },
        };
      }
      $ps->register_bundle(bundle)

    If you want to add or remove plugins, use hashref as usual: undef
    $bundle->{$plugin}; #remove a plugin using package name
    $bundle->{'My::Plugin'}={phase=>'foo'}; #add another plugin

    To facilitate inheritance of your plugins perhaps you put the hashref in
    a separate sub, so a child bundle can extend or remove plugins from
    yours.

  get_plugin
    Returns the plugin object associated with the phase. Returns undef on
    failure.

      $plugin=$ps->get_plugin ($phase);

  default_phase
    Makes a default phase from (the plugin's) class name. Expects a
    $plugin_class. Returns scalar or undef. If prefix is defined it use tail
    and removes all '::'. If no prefix is set default_phase returns the last
    element of the class name:

        $ps=Plugin-Tiny->new;
        $ps->default_phase(My::Plugin::Long::Example); # returns 'Example'

        $ps=Plugin-Tiny->new(prefix=>'My::Plugin::');
        $ps->default_phase(My::Plugin::Long::Example); # returns 'LongExample'

  get_class
    Returns the plugin's class.

      $class=$ps->get_class ($plugin);

    Todo: Not sure what it returns on error.

  get_phase
    returns the plugin's phase. Returns undef on failure. Normally, you
    should not need this: $phase=$ps->get_phase ($plugin);

Recommendation: First Register Then Do Things
    Plugin::Tiny suggests that you first register (load) all your plugins
    before you actually do something with them. Internal "require" / "use"
    of your packages is deferred until runtime. You can control the order in
    which plugins are loaded (in the order you call "register"), but if you
    manage to load all of them before you do anything, you can forget about
    order.

    You may know Plugin::Tiny's phases at compile time, but not which
    plugins will be loaded.

Recommendation: Require a Plugin Role
    You may want to do a plugin role for all you plugins, e.g. to
    standardize the interface for your plugins. Perhaps to make sure that a
    specific sub is available in the plugin:

      package My::Plugin; 
      use Moose;
      with 'Your::App::Role::Plugin';
      #...

Plugin Bundles
    You can create bundles of plugins if you pass the plugin system to the
    (bundling) plugin. That way you can load multiple plugins for one phase.
    You still need unique phases for each plugin:

      package My::Core;
      use Moose; 
      has 'plugin_system'=>(
        is=>'ro',
        isa=>'Plugin::Tiny', 
        default=>sub{Plugin::Tiny->new},
      );

      sub BUILD {
        $self->plugins->register(
          plugin=>'PluginBundle', 
          phase=>'Bundle',
          plugin_system=>$self->plugins, 
        );
      }

      #elsewhere in core
      my $b=$self->plugin_system->get_plugin ('Bundle');  
      $b->start();


      package PluginBundle;
      use Moose;
      has 'plugin_system'=>(is=>'ro', isa=>'Plugin::Tiny', required=>1); 

      sub bundle {
          {Plugin::One=>{},Plugin::Two=>{}}
      }  
      sub BUILD {
        #phase defaults to 'One' and 'Two':
        $self->plugins->register_bundle(bundle());
  
        #more or less the same as:    
        #$self->plugins->register (plugin=>'Plugin::One');  
        #$self->plugins->register (plugin=>'Plugin::Two'); 
      }
  
      sub start {
        my $one=$self->plugins->get('One');
        $one->do_something(@args);  
      }

AUTHOR
    Maurice Mengel <mauricemengel@gmail.com>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2012 by Maurice Mengel.

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