The event-glue Reference Manual

Next: , Previous: , Up: (dir)   [Contents][Index]

The event-glue Reference Manual

This is the event-glue Reference Manual, version 0.1.0, generated automatically by Declt version 4.0 beta 2 "William Riker" on Mon Aug 15 04:30:41 2022 GMT+0.

Table of Contents


1 Introduction

event-glue: simple eventing abstraction

event-glue is a library that offers simple abstraction around event processing. It's goal is to be compact, performant, extendable, and make no assumptions about your eventing infrastructure. It currently has no dependencies.

It is used in turtl-core to provide the main fabric of communication between various pieces of the app. It can be used anywhere you need a generic event handling system.

Why?

Eventing can be a great way to organize code.

Let's say you have an app. This app has a view (HTML, GTK, whatever). That view has a button. When the button is clicked, you have to run three different functions: launch-nuke, notify-president, lock-fallout-shelter. Now let's say you need to add another view to your app. This view also has a button, that when pressed, needs to do some things specific to that particular view, as well as run your three functions from earlier.

You can do a few things:

  1. Duplicate the calls to the launch-nuke, notify-president, and lock-fallout-shelter. After all, it's only three functions, right? Well if you need to add another function to call later, you have to remember to update all the places that call your function set.
  2. Abstract the functions calls inside of another function. This is a fine solution, but can end up giving you weird trees of functions that do similar things.
  3. Use eventing. Instead of calling your functions directly, you create and trigger a new event "red-button-pressed." Then you set up bindings to that event which tie the firing of the event to the specific actions that need to be called when it's fired. This offers strong decoupling of your interfaces. Instead of the button needing to know what to run, it just fires an event and each function is responsible for acting on it.
(defun launch-nuke (ev) ...)
(defun notify-president (ev) ...)
(defun lock-fallout-shelter (ev) ...)

(bind "red-button-pressed" 'launch-nuke)
(bind "red-button-pressed" 'notify-president)
(bind "red-button-pressed" 'lock-fallout-shelter)

(defun red-button-pressed ()
  (trigger (event "red-button-pressed")))

The next time we add a red button to another interface, all we have to do is run the same trigger: (trigger (event "red-button-pressed")) and our functions will fire automatically.

You can use eventing as much or as little as you want...your entire application can be based on cascading triggering of events or you can just use it for simple one-off cases. Either way, it can be a useful tool for just about any project.

How?

event-glue can be used two ways:

  1. Globally triggering events on your whole app
  2. Triggering events on specific objects

Global triggering:

;; when the database is finished initializing, apply our schema
(bind "db-init" apply-schema)

;; initialize the db, triggering "db-init" when done
(init-my-db :when-finished (lambda () (trigger (event "db-init"))))

Triggering on specific objects:

;; create our own class that extends `dispatch`
(defclass user (dispatch)
  ((name :accessor name :initarg :name :initform "slappy")))

;; create the user and bind to its "login" event
(defparameter *user* (make-instance 'user))
(bind "login" (lambda (ev) (format t "user ~a logged in~%" (car (data ev)))) :on *user*)

;; show our fictional interface, and once they login, trigger our event
(show-login :login-cb (lambda (username password)
                        ;; forward the username/password to our bindings via
                        ;; the event `:data` keyword
                        (trigger (event "login" :data (list username password))
                                 :on *user*)))

API

dispatch (class)

dispatch is an opaque class. It is an object that matches events to event bindings. All event bindings live in a dispatcher, and all events that are triggred are triggered on a dispatcher. It is the backbone of event-glue and all events flow through a dispatcher.

It can be easily extended by other classes to give you eventing on those objects.

It has no public accessors, but is exported so you can expand it within your app to add things like a synchronized queue.

Note that dispatchers can feed events into each other, either by passing all events or using a function to filter them (see forward).

*dispatch* (object of type dispatch)

This is the global default event dispatcher. If you use the bind or trigger functions without specifying the :on keyword, *dispatch* is used.

It is created on load via defvar meaning that subsequent loads will preserve the object. It is exported so that in the event you want to extend the dispatch class, you can create your own dispatch object and set it into event-glue:*dispatch* and everything will use your extended class by default.

make-dispatch (function)

(defun make-dispatch ())
  => dispatch

This function creates a new dispatcher.

forward (function)

(defun forward (from to-or-function))
  => nil

Sets up a forward between two dispatchers. from is the dispatcher that we want to forward events from, to-or-function can be either

Note that if A forward to B, triggering an event on A will fire A's handlers before the events are forwarded to B.

Example:

(let* ((all-events (make-dispatch))
       (click-events (make-dispatch))
       (hub (make-dispatch)))
  ;; all-events will get *all* events that hub gets
  (forward hub all-events)
  ;; click-events will only get events where the event name is "click"
  (forward hub
    (lambda (event)
      (when (string= (ev event) "click")
        click-events))))

forwardsp (function)

(defun forwardsp (from to-or-function))
  => to-or-function/nil

Test if from forwards to to-or-function

unforward (function)

(defun unforward (from to-or-function))
  => nil

Undoes a forward created by forward. The to-or-function object must be eq to the one used to set up the forward, or it will not be removed.

Example:

(let ((main (make-dispatch))
      (hub (make-dispatch)))
  (forward hub main)
  (unforward hub main))

event (class)

This class holds information about an event. This consists of the event's name, the event's data (which is an arbitrary object), and any metadata associated with the event. The class is public, allowing you to extend it and add any extra fields required to it (such as a UUID field).

Events are created using the event function, and are generally passed to trigger (or they could be serialized and sent off somewhere).

Events have three public accessors:

ev (accessor)

The event's name, generally a string.

data (accessor)

The event's data. This can be a number, a string, a list...anything you want. There are no restrictions on the data an event can hold.

meta (accessor)

This is a hash-table that consists of information about the event that doesn't necesarily fit into the event's data. For instance, you may want to mark what source an event came from in you app, but that information doesn't pertain to the event's data payload.

event (function)

(defun event (name &key data meta (type 'event)))
  => event

Create a new event object with the given name, data, and meta. name is generally a string, although if you wish you can use symbols or keywords as well. data can be any object you want to attach to the event. meta can be either a hash table or a plist (if plist, key names are string-downcaseed) that gives extra information about the event.

event also takes a :type keyword (which defaults to event) that allows you to create an event of your own type (for instance, you may extend event and use your-event to create event instances).

Example:

(event "click" :data '(:button-id 10) :meta '(:mouse-click t))

;; extension example
(defclass my-event (event) ())
(event "burnourcorruptcapitalistsystemdowntotheground" :type 'my-event)

bind (function)

(defun bind (event-name function &key name (on *dispatch*)))
  => function, unbind-function

Bind function to the given event-name on the dispatch object. This means that whenever trigger is called on dispatch with that event-name, function will be called.

If you pass :* as the event name, you can bind a catch-all event, meaning that your binding is triggered for every event that goes through the dispatcher.

function must take one argument, which will be the event object that was triggered.

The :name keyword allows you to "name" a binding. This is useful when you want to bind an event to anonymous function but you don't want to keep a reference to the function around if you need to unbind (which you'd normally have to do, see unbind). Instead, you can name a binding and then unbind that function with the same name later. The name you pass is converted to a string, so the names :test-event and "test-event" will ultimately resolve to the same name. Be aware of this when naming events.

Note that specifying an event-name/:name pair that already exists will overwrite the existing event binding.

Note that if multiple bindings are attached to the same event, the bindings are fired in the order they were added.

Returns the passed function and also a second function of 0 args that, when called, unbinds the event.

Examples:

;; bind the click-handler function to the "click" event on the global dispatch
(bind "click" 'click-handler)

;; bind to all events
(bind :* (lambda (ev) (format t "got event: ~a~%" ev)))

;; create our own dispatch and bind to the "close" event on it.
(let ((my-dispatch (make-dispatch)))
  (bind "close" (lambda (event) (format t "closed: ~a~%" event)) :on my-dispatch))

;; use named events to unbind an anonymous lambda
(bind "fire" (lambda (ev) (format t "JETSON, ...")) :name "fire:jetson")
;...
(unbind "fire" "fire:jetson")

bind-once (function)

(defun bind-once (event-name function &key name (on *dispatch*)))
  => function, unbind-function

Almost exactly like bind, except that the binding only lasts for one triggering (or until it's removed).

Returns the passed function and also a second function of 0 args that, when called, unbinds the event.

Example:

(bind-once "call" (lambda (ev) (format t "call from ~a~%" (data ev))))
(trigger (event "call" :data "sally"))  ; hi, sally
(trigger (event "call" :data "frank"))  ; frank's call is ignored

unbind (function)

(defun unbind (event-name function-or-name &key (on *dispatch*)))
  => t/nil

Unbind function-or-name from the event-name on the dispatch object. This is essentially the opposite of bind, allowing us to no longer have the given function (or binding name) triggered when the given event-name is triggered.

Returns T if a binding was removed, nil if no changes were made.

Example:

;; bind/unbind using a function
(let ((my-click-fn (lambda (event) (format t "clicked button: ~a~%" (data event)))))
  (bind "click" my-click-fn)
  (unbind "click" my-click-fn))

;; bind/unbind using a named binding
(bind "click" (lamdbda (event) (format t "clicked: ~a~%" (data event))) :name "click:format")
(unbind "click" "click:format")

unbind-all (function)

(defun unbind-all (event-name &key (on *dispatch*)))
  => nil

Unbind all events of type event-name on the dispatcher.

Example:

(bind "click" 'my-click-handler)
(bind "click" 'my-other-click-handler)
(bind "throw" 'ball-was-thrown)
(unbind-all "click")
;; *dispatch* now only contains a handler for "throw"

wipe (function)

(defun wipe (&key preserve-forwards (on *dispatch*)))
  => nil

Wipe out a dispatch object. This includes all handlers of all types.

If :preserve-forwards is true, then the dispatch object will maintain its relationships to other dispatch objects. Otherwise, forwards are removed as well (see forward).

trigger (function)

(defun trigger (event &key (on *dispatch*)))
  => nil

Finally, trigger is what we use to actually fire events.

Examples:

(bind "click" (lambda (event) (format t "clicked: ~a~%" (data event))))
(bind "click" (lambda (event) (format t "click!~%")))
(trigger (event "click" :data 'red-button))

Tests

Load up the event-glue-test system and run (event-glue-test:run-tests).

License

MIT.


2 Systems

The main system appears first, followed by any subsystem dependency.


Previous: , Up: Systems   [Contents][Index]

2.1 event-glue

A simple framework for event-based architectures.

Author

Andrew Danger Lyon <orthecreedence@gmail.com>

License

MIT

Version

0.1.0

Source

event-glue.asd.

Child Components

3 Files

Files are sorted by type and then listed depth-first from the systems components trees.


Previous: , Up: Files   [Contents][Index]

3.1 Lisp


Next: , Previous: , Up: Lisp   [Contents][Index]

3.1.1 event-glue/event-glue.asd

Source

event-glue.asd.

Parent Component

event-glue (system).

ASDF Systems

event-glue.


3.1.2 event-glue/package.lisp

Source

event-glue.asd.

Parent Component

event-glue (system).

Packages

event-glue.


3.1.3 event-glue/event.lisp

Dependency

package.lisp (file).

Source

event-glue.asd.

Parent Component

event-glue (system).

Public Interface
Internals

4 Packages

Packages are listed by definition order.


Previous: , Up: Packages   [Contents][Index]

4.1 event-glue

Source

package.lisp.

Nickname

ev

Use List

common-lisp.

Public Interface
Internals

5 Definitions

Definitions are sorted by export status, category, package, and then by lexicographic order.


Next: , Previous: , Up: Definitions   [Contents][Index]

5.1 Public Interface


5.1.1 Special variables

Special Variable: *dispatch*

Our global dispatch handler. This is the default handler used if a dispatcher is not specified in event operations.

Package

event-glue.

Source

event.lisp.


5.1.2 Ordinary functions

Function: bind (event-name function &key name on)

Bind a function to an event. Optionally allows naming the binding so it can be removed later on without the reference to the bound function.

Package

event-glue.

Source

event.lisp.

Function: bind-once (event-name function &key name on)

Bind a function to an event, but clear the binding out once the event has been triggered once.

Package

event-glue.

Source

event.lisp.

Function: event (name &key data meta type)

Easy wrapper for creating a standard event object. Meta is a plist of optional data to set (top-level) into the event object.

Package

event-glue.

Source

event.lisp.

Function: forward (from to-or-function)

Forward events from one dispatcher to another. If the second dispatcher is given as a function, that function must return either another dispatcher or nil. This lets you forward specific events at runtime based on data within the event.

Package

event-glue.

Source

event.lisp.

Function: forwardsp (from to-or-function)

Determine if the given from -> to forward is active. Returns either to-or-function or nil.

Package

event-glue.

Source

event.lisp.

Function: make-dispatch (&optional type)

Make a dispatcher.

Package

event-glue.

Source

event.lisp.

Function: trigger (event &key on)

Trigger en event.

Package

event-glue.

Source

event.lisp.

Function: unbind (event-name function-or-name &key on)

Unbind an event/function pair. If function-or-name contains a non-function value, the value is used in a name lookup instead. This allows removing an event/function binding by its name (as specified by :name in the bind function) which can be nice when the original lambda is no longer around.

Package

event-glue.

Source

event.lisp.

Function: unbind-all (event-name &key on)

Unbind all handlers for the given event name.

Package

event-glue.

Source

event.lisp.

Function: unforward (from to-or-function)

Undo a forward created by forward.

Package

event-glue.

Source

event.lisp.

Function: wipe (&key preserve-forwards on)

Wipe out all handlers for a dispatch object.

Package

event-glue.

Source

event.lisp.


5.1.3 Generic functions

Generic Reader: data (object)
Generic Writer: (setf data) (object)
Package

event-glue.

Methods
Reader Method: data ((event event))
Writer Method: (setf data) ((event event))

Arbitrary data attached to the event. Usually a set of args.

Source

event.lisp.

Target Slot

data.

Generic Reader: ev (object)
Generic Writer: (setf ev) (object)
Package

event-glue.

Methods
Reader Method: ev ((event event))
Writer Method: (setf ev) ((event event))

Holds the event’s name.

Source

event.lisp.

Target Slot

ev.

Generic Reader: meta (object)
Generic Writer: (setf meta) (object)
Package

event-glue.

Methods
Reader Method: meta ((event event))
Writer Method: (setf meta) ((event event))

Any top-level meta associated with the event, used to describe it.

Source

event.lisp.

Target Slot

meta.


5.1.4 Standalone methods

Method: print-object ((event event) s)
Source

event.lisp.


5.1.5 Classes

Class: dispatch

The dispatch class is what event listeners bind to. Events flow throw it.

Package

event-glue.

Source

event.lisp.

Direct methods
Direct slots
Slot: handlers

Holds the dispatcher’s event handlers (event-name -> fn).

Initform

(make-hash-table :test (function equal))

Readers

dispatch-handlers.

Writers

(setf dispatch-handlers).

Slot: handler-names

Holds named event name -> fn bindings for easy lookups.

Initform

(make-hash-table :test (function equal))

Readers

dispatch-handler-names.

Writers

(setf dispatch-handler-names).

Slot: forwards

Holds any other dispatchers this dispatcher forwards to.

Initargs

:forwards

Readers

dispatch-forwards.

Writers

(setf dispatch-forwards).

Class: event

Describes an event and any data it holds.

Package

event-glue.

Source

event.lisp.

Direct methods
Direct slots
Slot: ev

Holds the event’s name.

Initargs

:ev

Readers

ev.

Writers

(setf ev).

Slot: data

Arbitrary data attached to the event. Usually a set of args.

Initargs

:data

Readers

data.

Writers

(setf data).

Slot: meta

Any top-level meta associated with the event, used to describe it.

Initform

(make-hash-table :test (function equal))

Initargs

:meta

Readers

meta.

Writers

(setf meta).


5.2 Internals


Next: , Previous: , Up: Internals   [Contents][Index]

5.2.1 Ordinary functions

Function: make-lookup-name (event-name name)

Standardizes the naming convention for named event names.

Package

event-glue.

Source

event.lisp.


5.2.2 Generic functions

Generic Reader: dispatch-forwards (object)
Generic Writer: (setf dispatch-forwards) (object)
Package

event-glue.

Methods
Reader Method: dispatch-forwards ((dispatch dispatch))
Writer Method: (setf dispatch-forwards) ((dispatch dispatch))

Holds any other dispatchers this dispatcher forwards to.

Source

event.lisp.

Target Slot

forwards.

Generic Reader: dispatch-handler-names (object)
Generic Writer: (setf dispatch-handler-names) (object)
Package

event-glue.

Methods
Reader Method: dispatch-handler-names ((dispatch dispatch))
Writer Method: (setf dispatch-handler-names) ((dispatch dispatch))

Holds named event name -> fn bindings for easy lookups.

Source

event.lisp.

Target Slot

handler-names.

Generic Reader: dispatch-handlers (object)
Generic Writer: (setf dispatch-handlers) (object)
Package

event-glue.

Methods
Reader Method: dispatch-handlers ((dispatch dispatch))
Writer Method: (setf dispatch-handlers) ((dispatch dispatch))

Holds the dispatcher’s event handlers (event-name -> fn).

Source

event.lisp.

Target Slot

handlers.


Appendix A Indexes


Next: , Previous: , Up: Indexes   [Contents][Index]

A.1 Concepts


Next: , Previous: , Up: Indexes   [Contents][Index]

A.2 Functions

Jump to:   (  
B   D   E   F   G   M   P   T   U   W  
Index Entry  Section

(
(setf data): Public generic functions
(setf data): Public generic functions
(setf dispatch-forwards): Private generic functions
(setf dispatch-forwards): Private generic functions
(setf dispatch-handler-names): Private generic functions
(setf dispatch-handler-names): Private generic functions
(setf dispatch-handlers): Private generic functions
(setf dispatch-handlers): Private generic functions
(setf ev): Public generic functions
(setf ev): Public generic functions
(setf meta): Public generic functions
(setf meta): Public generic functions

B
bind: Public ordinary functions
bind-once: Public ordinary functions

D
data: Public generic functions
data: Public generic functions
dispatch-forwards: Private generic functions
dispatch-forwards: Private generic functions
dispatch-handler-names: Private generic functions
dispatch-handler-names: Private generic functions
dispatch-handlers: Private generic functions
dispatch-handlers: Private generic functions

E
ev: Public generic functions
ev: Public generic functions
event: Public ordinary functions

F
forward: Public ordinary functions
forwardsp: Public ordinary functions
Function, bind: Public ordinary functions
Function, bind-once: Public ordinary functions
Function, event: Public ordinary functions
Function, forward: Public ordinary functions
Function, forwardsp: Public ordinary functions
Function, make-dispatch: Public ordinary functions
Function, make-lookup-name: Private ordinary functions
Function, trigger: Public ordinary functions
Function, unbind: Public ordinary functions
Function, unbind-all: Public ordinary functions
Function, unforward: Public ordinary functions
Function, wipe: Public ordinary functions

G
Generic Function, (setf data): Public generic functions
Generic Function, (setf dispatch-forwards): Private generic functions
Generic Function, (setf dispatch-handler-names): Private generic functions
Generic Function, (setf dispatch-handlers): Private generic functions
Generic Function, (setf ev): Public generic functions
Generic Function, (setf meta): Public generic functions
Generic Function, data: Public generic functions
Generic Function, dispatch-forwards: Private generic functions
Generic Function, dispatch-handler-names: Private generic functions
Generic Function, dispatch-handlers: Private generic functions
Generic Function, ev: Public generic functions
Generic Function, meta: Public generic functions

M
make-dispatch: Public ordinary functions
make-lookup-name: Private ordinary functions
meta: Public generic functions
meta: Public generic functions
Method, (setf data): Public generic functions
Method, (setf dispatch-forwards): Private generic functions
Method, (setf dispatch-handler-names): Private generic functions
Method, (setf dispatch-handlers): Private generic functions
Method, (setf ev): Public generic functions
Method, (setf meta): Public generic functions
Method, data: Public generic functions
Method, dispatch-forwards: Private generic functions
Method, dispatch-handler-names: Private generic functions
Method, dispatch-handlers: Private generic functions
Method, ev: Public generic functions
Method, meta: Public generic functions
Method, print-object: Public standalone methods

P
print-object: Public standalone methods

T
trigger: Public ordinary functions

U
unbind: Public ordinary functions
unbind-all: Public ordinary functions
unforward: Public ordinary functions

W
wipe: Public ordinary functions

Jump to:   (  
B   D   E   F   G   M   P   T   U   W