Events

Ferris has a very simple global pubsub-style event system. Beyond the events emitted by Controllers and Views there’s also a way to globally emit and respond to events.

listeners.py

app/listeners.py is used to register global event listeners using on:

ferris.core.events.on(event_name)[source]

Automatically called when the specified event occurs.

For example, to switch from the default theme:

@on('controller_before_startup')
def before_startup(controller, *args, **kwargs):
    controller.meta.view.theme = 'corny'

All controller events are prefixed with controller_ when broadcast globally.

Emitting Events

You can emit events on the global bus by using fire:

ferris.core.events.fire(event_name, *args, **kwargs)[source]

Calls all of the registered event handlers for a given event. Passes through all arguments

For example:

@route
def transmat(self, item):
    fire("item_transmat", item)

Examples

There are some very useful cases for using the global event bus.

Setting theme globally

As shown above this sets the theme for every controller:

@on('controller_before_startup')
def before_startup(controller, *args, **kwargs):
    controller.meta.view.theme = 'corny'

Injecting components

If you’d like every controller to contain a particular component:

@on('controller_before_build_components')
def inject_components(controller, *args, **kwargs):
    if not MyComponent in controller.Meta.components:
        controller.Meta.components += (MyComponent,)

Injecting authorization chains

If you’d like every controller to have a particular authorization chain:

@on('controller_before_authorization')
def inject_chains(controller, authorizations):
    if not my_chain in authorizations:
        authorizations.append(my_chain)

For example, if you’d like to lock down your application to a particular Google Apps domains:

def domain_chain(controller):
    user = controller.user
    if not user:
        return False, "You must be logged"

    email_domain = user.email().split('@')[1]

    if not email_domain in ('sherpademo.com', 'google.com'):
        return False, "Your domain does not have access"

    return True

@on('controller_before_authorization')
def inject_authorization_chains(controller, authorizations):
    authorizations.insert(0, domain_chain)

Exposing template data

If you’d like every template to have access to some particular data:

@on('controller_before_render')
def before_render(controller):
    controller.context['custom_data'] = something.get_data()