
Plugin Extension
================

As gofer plugins are written and shared throughout the open source community, it seems likely that
rather than writing your plugin from scratch, it would be useful to be able to extend one that already
exists. Plugins have an API for extending their *remote* API with *remote* objects provided by other
plugins.  Plugin extension can also be specified in the plugin *descriptor* using the *extends*
property


Extending
^^^^^^^^^

What can be imported:

- class object
- function object


**Using the descriptor property:**


Example:

plugin: **dog** can extend the **animals** plugin.  Using this method will add all of the *dog* API
to the *animals* API.

::

 [main]
 enabled=1
 extends=animals


**Using the API:**


Example:

plugin: **animals**

::

 class Dog:
    @remote
    def bark(self):
        pass


plugin: **myplugin**

::

 from gofer.agent.plugin import Plugin

 animals = Plugin.find('animals')
 plugin = Plugin.find(__name__)

 # just import Dog
 plugin += animals['Dog']

 # import everything
 plugin += animals


Inheritance
^^^^^^^^^^^

Imported class objects may be used as if imported using the standard *import* directive.  When used
as a *superclass*, the inherited methods will be exposed (@remote) as decorated in the superclass.

Examples:

::

 from gofer.agent.plugin import Plugin

 # import Dog from animals plugin

 animals = Plugin.find('animals')
 Dog = animals['Dog']

 class Retriever(Dog):
    @remote(secret='wagf')
    def fetch(self):
        pass


Results in the following *remote* API:

Retriever:

- bark()
   - auth: *None*
- fetch()
   - auth: *shared secret*

However, notice that the *auth* on the inherited bark() is different than fetch().
To change this, simply override the method and re-decorate as needed:

::

 from gofer.agent.plugin import Plugin

 # import Dog from animals plugin

 animals = Plugin.find('animals')
 Dog = animals['Dog']

 class Retriever(Dog):

    @remote(secret='wag')
    def bark(self):
        Dog.bark(self)

    @remote(secret='wag')
    def fetch(self):
        pass


Delegation
^^^^^^^^^^

In many cases, plugins may choose to leverage imported objects by delegation rather than inheritance.

In this example, the Old McDonald toy does not extend *Dog* but rather delegates the functionality
of a dog bark() to an instance of Dog:

::

 from gofer.agent.plugin import Plugin

 # import Dog from animals plugin

 animals = Plugin.find('animals')
 Dog = animals['Dog']

 # Old McDonald toy
 class Toy:
    @remote
    def theDog(self):
        dog = Dog()
        dog.bark()

