=========================================
Writing TurboGears Extensions
=========================================

TurboGears provides a bunch of hook points and ways to extend the framework behavior
to write extensions. Most of the needs can usually be satisfied by relying on
:class:`tg.configuration.AppConfig`, :ref:`config_milestones` and :ref:`Hooks<hooks_and_events>`.

Creating an Extension
=================================

TurboGears extensions are identified by the ``tgext.*`` package name, since
version 2.3.2 the devtools provide a command to quickly create a new TurboGears
extension which can be both used by itself or plugged through ``tgext.pluggable``.

To quickstart the extension run::

    $ gearbox tgext -n myextension -a "My Name" -e "my@email.com"

This will create a ``tgext.myextension`` directory which a simple sample extension
inside. To tune the author, description, license of your extension have a look
at the ``tgext`` command options using ``gearbox help tgext``.

Tuning on the Extension
==================================

If you created the ``tgext.myextension`` using the ``tgext`` command you can
quickly turn it on by editing your application ``config/app_cfg.py`` and appending
at the end the following lines::

    import tgext.myextension
    tgext.myextension.plugme(base_config)

of through the *pluggable application* interface if ``tgext.pluggable`` is available::

    from tgext.pluggable import plug
    plug(base_config, 'tgext.myextension')

By enabling the autogenerated extension and starting ``gearbox serve`` again,
you will notice that it just provides a bunch of logging hooks and not much more::

    17:52:30,019 INFO  [tgext.myextension] Setting up tgext.myextension extension...
    17:52:30,023 INFO  [tgext.myextension] >>> Public files path is /home/USER/myapp/myapp/public
    17:52:30,023 INFO  [tgext.myextension] + Application Running!
    17:52:30,040 INFO  [gearbox] Starting server in PID 22484.
    Starting HTTP server on http://0.0.0.0:8080
    17:52:30,740 INFO  [tgext.myextension] Serving: /

The Sample Extension
==================================

The sample extension created by the ``tgext`` command provides its actual setup
inside the ``__init__.py`` file. This file showcases some of the extension
points provided by TurboGears.

If you actually created ``tgext.myextension`` you should get a
``tgext.myextension/tgext/myextension/__init__.py`` file with the following content::

    from tg import config
    from tg import hooks
    from tg.configuration import milestones

    import logging
    log = logging.getLogger('tgext.myextension')


    # This is the entry point of your extension, will be called
    # both when the user plugs the extension manually or through tgext.pluggable
    # What you write here has the same effect as writing it into app_cfg.py
    # So it is possible to plug other extensions you depend on.
    def plugme(configurator, options=None):
        if options is None:
            options = {}

        log.info('Setting up tgext.myextension extension...')
        milestones.config_ready.register(SetupExtension(configurator))

        return dict(appid='tgext.myextension')


    # Most of your extension initialization should probably happen here,
    # where it's granted that .ini configuration file has already been loaded
    # in tg.config but you can still register hooks or other milestones.
    class SetupExtension(object):
        def __init__(self, configurator):
            self.configurator = configurator

        def __call__(self):
            log.info('>>> Plugin files path is %s' % config['paths']['static_files'])
            hooks.register('startup', self.on_startup)

            def echo_wrapper_factory(handler, config):
                def echo_wrapper(controller, environ, context):
                    log.info('Serving: %s' % context.request.path)
                    return handler(controller, environ, context)
                return echo_wrapper

            # Application Wrappers are much like easier WSGI Middleware
            # that get a TurboGears context and return a Response object.
            self.configurator.register_wrapper(echo_wrapper_factory)

        def on_startup(self):
            log.info('+ Application Running!')

The core parts of the previous example are:

    * **plugme function**, this is the function used to turn on your extension.
        will be automatically called by ``tgext.pluggable`` when the extension
        is enabled using the *pluggable application* interface or by the
        user itself when manually enabling your extension. Inside this
        method the application configurator (AppConfig) object is available
        and the options the user specified for the extension, but not application
        configuration as it has not been loaded yet.

    * **SetupExtension.__call__**, this is a callable that is registered
        by the **plugme** function for the ``config_read`` milestone so that it
        is executed when the *.ini* configuration has been loaded and merged with
        the options declared through the application configurator in *config/app_cfg.py*.

        Here you can register additional milestones, functions or access and
        modify the application configurator through the ``self.configurator``
        object.

    * **SetupExtension.on_startup** This is a sample hook registered on
        application startup by ``SetupExtension.__call__`` that says hello
        when the application has started. Have at look at :ref:`Hooks<hooks_and_events>`
        for a complete list of available hooks.

Extensions with models and controllers
=========================================

If your extension needs to expose models and controllers you probably want to have a look at
**Pluggable Applications** which are meant to create reusable turbogears applications that
can be plugged inside other applications to extend their features.

=========================================
Pluggable Applications with TurboGears
=========================================

TurboGears 2.1.4 introduced support for pluggable applications using tgext.pluggable.
``tgext.pluggable`` is now the official supported way in TurboGears to create pluggable
reusable applications.
Currently only SQLAlchemy based applications are supported as pluggable applications.

Official documentation for ``tgext.pluggable`` can be found at: http://pypi.python.org/pypi/tgext.pluggable

Supported Features
==================================

Pluggable applications can define their own:

    * **controllers**, which will be automatically mounted when the application is purged.
    * **models**, which will be available inside and outside of the plugged application.
    * **helpers**, which can be automatically exposed in ``h`` object in application template.
    * **bootstrap**, which will be executed when `setup-app` is called.
    * **statics**, which will be available at their own private path.

Mounting a pluggable application
==================================

In your application config/app_cfg.py import ``plug`` from ``tgext.pluggable`` and
call it for each pluggable application you want to enable.

The plugged package must be installed in your environment.

.. code-block:: python

    from tgext.pluggable import plug
    plug(base_config, 'package_name')

Creating Pluggable Applications
===================================

``tgext.pluggable`` provides a **quickstart-pluggable** command
to create a new pluggable applications:

.. code-block:: bash

    $ gearbox quickstart-pluggable plugtest
    ...

The quickstarted application will provide an example on how to use
models, helpers, bootstrap, controllers and statics.


