"""
Abstract
--------

The pluggable library provides simple yet effective support for creating plugin functionality.

Usage
-----

Defining a Plugin
.................

By extending the :py:class:`commonkit.pluggable.library.PluginProvider` class, you are indicating that your class is a
plugin.

.. code-block:: python

    from commonkit.pluggable import PluginProvider

    class MyProvider(PluginProvider):
        pass

Of course, your provider must *do* something in order to be useful as a plugin. What it does and how it does it is
entirely up to you. The most important thing is that you document the expected methods and properties in your plugin
API.

Using a Manager
...............

The plugin manager is a utility that ensures plugin code is loaded and plugins are initialized at run time.

.. code-block:: python

    from commonkit.pluggable import PluginManager

    # Plugins are given using dotted path notation. This could come from a database or configuration file. Import errors
    # are suppressed, so the listed plugins need not exist in the Python path.
    enabled_plugins = [
        "path.to.plugin1",
        "path.to.plugin2",
        "path.to.plugin3",
    ]

    # Initialize the manager with the enabled plugins.
    manager = PluginManager(plugins=enabled_plugins)

    # The load method returns the number of plugin modules loaded.
    count = manager.load()
    print("Loaded %s plugins." % count)

Using Plugins
.............

In the example below, the ``WebPage`` class allows plugins to alter or even replace content generated by its
``get_content()`` method.

.. code-block:: python

    # Assume the manager may be loaded from a central location. The plugins import is an instantiated PluginManager.
    from local.plugins import plugins

    class WebPage(object):
        def get_content(object):
            # do normal things to get content ...
            content = load_file(self.path)

            # then let plugins do their thing ...
            for plugin in plugins:
                plugin.get_page_content(self, content=content)

            # then return the content ...
            return content

Your plugin classes must define a ``get_page_content()`` method or an ``AttributeError`` is raised. Again, the most
important thing is that you document the expected methods and properties in your plugin API.

Handling Different Types of Plugins
...................................

What happens if you want different types of plugins? For example, plugins that work only with a ``WebSite`` instance,
and others that work with ``WebPage``? You could accomplish this simply by creating a new instance of ``PluginManager``:

.. code-block:: python

    # For example, in website.sites ...
    from commonkit.pluggable import PluginProvider

    class WebSitePlugin(PluginProvider):
        # documentation and code specific to this provider

    # For example, in website.pages ...
    from commonkit.pluggable import PluginProvider

    class WebPagePlugin(PluginProvider):
        # documentation and code specific to this provider

    # Then in some location where code is always loaded ...
    from commonkit.pluggable import PluginManager
    from website.sites import WebSitePlugin
    from websites.pages import WebPagePlugin

    site_plugins = PluginManager(provider=WebSitePlugin)
    page_plugins = PluginManager(provider=WebPagePlugin)

Reference
---------

Much of the code in this library was inspired by `A Simple Plugin Framework`_ by Marty Alchin. This excellent article
discusses a simple and practical approach to pluggable behavior and is well worth reading.

.. _A Simple Plugin Framework: http://martyalchin.com/2008/jan/10/simple-plugin-framework/

"""
from .library import MountPoint, PluginManager, PluginProvider

__all__ = (
    "MountPoint",
    "PluginProvider",
    "PluginManager"
)

__version__ = "0.4.0-d"
