Next: Introduction, Previous: (dir), Up: (dir) [Contents][Index]
This is the cl-hooks Reference Manual, version 0.2.1, generated automatically by Declt version 3.0 "Montgomery Scott" on Tue Dec 22 11:41:53 2020 GMT+0.
• Introduction | What cl-hooks is all about | |
• Systems | The systems documentation | |
• Modules | The modules documentation | |
• Files | The files documentation | |
• Packages | The packages documentation | |
• Definitions | The symbols documentation | |
• Indexes | Concepts, functions, variables and data types |
#+TITLE: cl-hooks README #+AUTHOR: Jan Moringen #+EMAIL: jmoringe@techfak.uni-bielefeld.DE * Prelude :noexport: #+BEGIN_SRC lisp :session hooks (asdf:load-system :cl-hooks) #+END_SRC * Introduction A hook, in the present context, is a certain kind of [[http://wikipedia.org/wiki/Extension_point][extension point]] in a program that allows interleaving the execution of arbitrary code with the execution of a the program without introducing any coupling between the two. Hooks are used extensively in the extensible editor [[http://gnu.org/software/emacs][Emacs]]. In the Common LISP Object System (CLOS), a similar kind of extensibility is possible using the flexible multi-method dispatch mechanism. It may even seem that the concept of hooks does not provide any benefits over the possibilites of CLOS. However, there are some differences: + There can be only one method for each combination of specializers and qualifiers. As a result this kind of extension point cannot be used by multiple extensions independently. + Removing code previously attached via a :before, :after or :around method can be cumbersome. + There could be other or even multiple extension points besides :before and :after in a single method. + Attaching codes to individual objects using eql specializers can be cumbersome. + Introspection of code attached a particular extension point is cumbersome since this requires enumerating and inspecting the methods of a generic function. This library tries to complement some of these weaknesses of method-based extension-points via the concept of hooks. #+ATTR_HTML: :alt "build status image" :title Build Status :align right [[https://travis-ci.org/scymtym/architecture.hooks][https://travis-ci.org/scymtym/architecture.hooks.svg]] * Hooks ** Definition A hook is an extension point consisting of + A name (a symbol or some form) + A list of handlers + ftype? + A result combination + A documentation string There are several kinds of hooks defined in this library, but new kinds of hooks can easily be defined by adding methods to the generic functions =hook-handlers=, =(setf hook-handlers)=, =hook-combination=, =(setf hook-combination)=, =documentation= and =(setf documentation)=. The following sections briefly discuss the three kinds of hooks that are currently defined in the library. Mention documentation ** Variable Hooks The most straightforward approach to implementing a hook is to use a variable. The variable is used as followed + Symbol Name :: name of the hook + Symbol Value :: list of handlers currently attached to the hook + Symbol Documentation :: if no dedicated hook documentation is installed using =(setf (hook-documentation ...) ...)=, the documentation of the symbol as a variable is used Consider the following example #+BEGIN_SRC lisp :session hooks :exports both :results output (defvar *my-hook* nil "My hook is only run for educational purposes.") (hooks:add-to-hook '*my-hook* (lambda (x) (format t "my-hook called with argument ~S~%" x))) (hooks:run-hook '*my-hook* 1) #+END_SRC #+BEGIN_SRC lisp :session hooks :exports both :results value verbatim (documentation '*my-hook* 'hooks::hook) #+END_SRC ** Internal Object Hooks Hooks can also live in other places like object slots: #+BEGIN_SRC lisp :session hooks :exports both :results output (defclass my-class () ((my-hook :initarg :my-hook :type list :initform nil :documentation "This hook bla bla"))) (defvar *my-object* (make-instance 'my-class)) (hooks:object-hook *my-object* 'my-hook) #+END_SRC Operation on an intern object hook work in the usual way: #+BEGIN_SRC lisp :session hooks :exports both :results output (hooks:add-to-hook (hooks:object-hook *my-object* 'my-hook) (lambda (x) (format t "my-hook called with argument ~S~%" x))) (hooks:object-hook *my-object* 'my-hook) #+END_SRC #+BEGIN_SRC lisp :session hooks :exports both :results output (format t "bla~%") (hooks:run-hook (hooks:object-hook *my-object* 'my-hook) 1) #+END_SRC For object internal hooks, the documentation of the backing slot is used as the hook's documentation: #+BEGIN_SRC lisp :session hooks :exports both :results value verbatim (documentation (hooks:object-hook *my-object* 'my-hook) 'hooks::hook) #+END_SRC ** External Object Hooks Or outside of objects: #+BEGIN_SRC lisp :session hooks :exports both :results value (defparameter *external-hook* (hooks:external-hook *my-object* 'my-external-hook)) *external-hook* #+END_SRC We stored the hook object in a variable since we are going to use it in some other examples. #+BEGIN_SRC lisp :session hooks :exports both :results output (hooks:add-to-hook *external-hook* (lambda (x) (format t "my-external-hook called with argument ~S~%" x))) (hooks:run-hook *external-hook* 1) #+END_SRC ** Hook Combination Hook combination refers to the different possible way of constructing the resulting value of running a hook. While bearing a strong resemblance to method combination in CLOS namewise, hook combination is a much more restricted and less powerful concept. The default hook combination is =progn=: #+BEGIN_SRC lisp :session hooks :exports both :results output (hooks:hook-combination (hooks:external-hook *my-object* 'my-external-hook)) #+END_SRC =progn= hook combination means the final result is the return value of the handler run last: TODO Let's set up the hook to test some other combinations #+BEGIN_SRC lisp :session hooks :exports both :results output (hooks:clear-hook *external-hook*) (hooks:add-to-hook *external-hook* #'(lambda (x) (mod x 5))) (hooks:add-to-hook *external-hook* #'(lambda (x) (- x))) #+END_SRC + Combination using =list= :: #+BEGIN_SRC lisp :session hooks :exports both :results output verbatim (setf (hooks:hook-combination *external-hook*) #'list) (list (hooks:run-hook *external-hook* -3) (hooks:run-hook *external-hook* 1) (hooks:run-hook *external-hook* 7)) #+END_SRC + Combination using =max= :: #+BEGIN_SRC lisp :session hooks :exports both :results output verbatim (setf (hooks:hook-combination *external-hook*) #'max) (list (hooks:run-hook *external-hook* -3) (hooks:run-hook *external-hook* 1) (hooks:run-hook *external-hook* 7)) #+END_SRC *Note*: #+BEGIN_QUOTE Some functions can be used for hook combination, but will not work as expected in all cases. =max= is one such examples. Running a hook with =max= hook combination that does not have any handlers will result in an error because =max= cannot be called without any arguments (which is the result of calling zero handlers). #+END_QUOTE * Tracking State #+BEGIN_SRC lisp :session hooks :exports both :results output (defmethod hooks:on-become-active :after ((hook t)) (format t "hook ~S is now active~%" hook)) (defmethod hooks:on-become-inactive :after ((hook t)) (format t "hook ~S is now inactive~%" hook)) (setf *my-object* (make-instance 'my-class)) (hooks:add-to-hook (hooks:object-hook *my-object* 'my-hook) (lambda (x))) (setf (hooks:hook-handlers (hooks:object-hook *my-object* 'my-hook)) nil) #+END_SRC * Restarts This library uses restart to recover from errors during the execution of hooks or their handlers. This section briefly discusses the restarts that are installed at the hook and handler levels. ** Hook Restarts + =retry= :: When this restart is invoked, the hook is ran again. + =use-value= :: When this restart is invoked, the hook is not ran and a replacement value is read interactively and returned in place of the result of running the hook. ** Handler Restarts + =retry= :: When this restart is invoked, the handler is executed again. + =use-value= :: When this restart is invoked, the handler is not executed and a replacement value is read interactively and returned in place of the result of executing the handler. + =skip= :: When this restart is invoked, the handler is skipped without producing any return value. If there are other handlers, the hook may still produce a return value. * Convenience Marcos #+BEGIN_SRC lisp (hooks:with-handlers (((hooks:external-hook *my-object* 'my-hook) (lambda (x))) ((hooks:external-hook *my-object* 'my-other-hook) (lambda (y z)))) (hooks:run-hook (hooks:external-hook *my-object* 'my-hook))) #+END_SRC * settings :noexport: #+LATEX_CLASS: scrartcl # Local Variables: # mode: org # End:
Next: Modules, Previous: Introduction, Up: Top [Contents][Index]
The main system appears first, followed by any subsystem dependency.
• The cl-hooks system |
Jan Moringen <jmoringe@techfak.uni-bielefeld.de>
Jan Moringen <jmoringe@techfak.uni-bielefeld.de>
LLGPLv3
This system provides the hooks extension point mechanism (as known, e.g., from GNU Emacs).
0.2.1
cl-hooks.asd (file)
src/early (module)
Modules are listed depth-first from the system components tree.
• The cl-hooks/src/early module |
cl-hooks (system)
src/
Files are sorted by type and then listed depth-first from the systems components trees.
• Lisp files |
Next: The cl-hooks/src/early/package․lisp file, Previous: Lisp files, Up: Lisp files [Contents][Index]
cl-hooks.asd
cl-hooks (system)
Next: The cl-hooks/src/early/conditions․lisp file, Previous: The cl-hooks․asd file, Up: Lisp files [Contents][Index]
Next: The cl-hooks/src/early/protocol․lisp file, Previous: The cl-hooks/src/early/package․lisp file, Up: Lisp files [Contents][Index]
package.lisp (file)
src/early (module)
src/conditions.lisp
Next: The cl-hooks/src/early/util․lisp file, Previous: The cl-hooks/src/early/conditions․lisp file, Up: Lisp files [Contents][Index]
conditions.lisp (file)
src/early (module)
src/protocol.lisp
Next: The cl-hooks/src/early/hook․lisp file, Previous: The cl-hooks/src/early/protocol․lisp file, Up: Lisp files [Contents][Index]
protocol.lisp (file)
src/early (module)
src/util.lisp
Next: The cl-hooks/src/early/state․lisp file, Previous: The cl-hooks/src/early/util․lisp file, Up: Lisp files [Contents][Index]
util.lisp (file)
src/early (module)
src/hook.lisp
Next: The cl-hooks/src/early/mixins․lisp file, Previous: The cl-hooks/src/early/hook․lisp file, Up: Lisp files [Contents][Index]
hook.lisp (file)
src/early (module)
src/state.lisp
Next: The cl-hooks/src/early/symbol․lisp file, Previous: The cl-hooks/src/early/state․lisp file, Up: Lisp files [Contents][Index]
state.lisp (file)
src/early (module)
src/mixins.lisp
Next: The cl-hooks/src/early/object-internal․lisp file, Previous: The cl-hooks/src/early/mixins․lisp file, Up: Lisp files [Contents][Index]
mixins.lisp (file)
src/early (module)
src/symbol.lisp
Next: The cl-hooks/src/early/object-external․lisp file, Previous: The cl-hooks/src/early/symbol․lisp file, Up: Lisp files [Contents][Index]
symbol.lisp (file)
src/early (module)
src/object-internal.lisp
Next: The cl-hooks/src/early/macros․lisp file, Previous: The cl-hooks/src/early/object-internal․lisp file, Up: Lisp files [Contents][Index]
object-internal.lisp (file)
src/early (module)
src/object-external.lisp
Previous: The cl-hooks/src/early/object-external․lisp file, Up: Lisp files [Contents][Index]
object-external.lisp (file)
src/early (module)
src/macros.lisp
Next: Definitions, Previous: Files, Up: Top [Contents][Index]
Packages are listed by definition order.
• The hooks package |
This package contains functions and classes which implement the
"hook" extension point mechanism as known, for example, from GNU
Emacs.
Hooks are first-class objects which can be inspected and modified via
accessors:
+ ‘hook-name’
+ ‘hook-handlers’
+ ‘hook-combination’
+ ‘run-hook’
+ ‘add-to-hook’
+ ‘remove-from-hook’
+ ‘clear-hook’
The builtin kinds of hooks are the following
+ list of handlers as value of a symbol
+ list of handlers in an object slot
+ hook object is associated to arbitrary Lisp object
package.lisp (file)
Definitions are sorted by export status, category, package, and then by lexicographic order.
• Exported definitions | ||
• Internal definitions |
Next: Internal definitions, Previous: Definitions, Up: Definitions [Contents][Index]
• Exported macros | ||
• Exported functions | ||
• Exported generic functions | ||
• Exported conditions | ||
• Exported classes |
Next: Exported functions, Previous: Exported definitions, Up: Exported definitions [Contents][Index]
Instantiate HOOK and set COMBINATION and DOCUMENTATION.
macros.lisp (file)
Execute BODY when the external hook named NAME becomes active. The keyword arguments object and hook can be used to name variables will be bound to the object and the hook object respectively during the execution of BODY.
macros.lisp (file)
Execute [DE]ACTIVATE when HOOK becomes [in]active respectively.
HOOK is a form that designates or retrieves a hook. Examples include a
symbol designating a hook stored in that symbol or a form
like (object-hook OBJECT HOOK-SYMBOL).
Within the forms ACTIVATE and DEACTIVATE, the variable VAR (when
specified) can be used to refer to the hook object (not HOOK, which is
a form to retrieve the hook object).
macros.lisp (file)
When HOOK becomes active, execute BODY which has to return a method object. When HOOK becomes inactive, the method is removed. The keyword argument VAR can be used to specify the name of a variable to which the hook object will be bound during the execution of BODY.
macros.lisp (file)
Execute ACTIVATE when internal HOOK of an instance of CLASS becomes active and execute DEACTIVATE when such a hook becomes inactive. The keyword arguments INSTANCE and HOOK can be used to name variables that will be bound to the instance and the hook object respectively during the execution of ACTIVATE and DEACTIVATE.
macros.lisp (file)
Run BODY with handlers as specified in HOOKS-AND-HANDLERS.
HOOKS-AND-HANDLERS is a list of items of the form (HOOK HANDLER) where
HOOK is a hook and HANDLER is coercable to a function.
Example:
((with-handlers (((object-external object ’hook)
(lambda (args)
(format t "~S~%" args))))
(do-something))
macros.lisp (file)
Next: Exported generic functions, Previous: Exported macros, Up: Exported definitions [Contents][Index]
Run HOOK with ARGS like ‘run-hook’, with the following differences:
+ do not run any methods installed on ‘run-hook’
+ do not install any restarts
+ do not collect or combine any values returned by handlers.
Next: Exported conditions, Previous: Exported functions, Up: Exported definitions [Contents][Index]
Add HANDLER to HOOK.
protocol.lisp (file)
hook.lisp (file)
Remove all handlers from HOOK.
protocol.lisp (file)
hook.lisp (file)
Combine RESULTS of running HOOK’s handlers according to COMBINATION.
protocol.lisp (file)
hook.lisp (file)
hook.lisp (file)
Return a representation of the slot residing outside of OBJECT under the name HOOK.
object-external.lisp (file)
Return the hook combination used by HOOK.
protocol.lisp (file)
(setf hook-combination) (generic function)
symbol.lisp (file)
The hook combination used by this hook.
mixins.lisp (file)
hook.lisp (file)
Install NEW-VALUE as the hook combination used by HOOK.
protocol.lisp (file)
hook-combination (generic function)
symbol.lisp (file)
The hook combination used by this hook.
mixins.lisp (file)
conditions.lisp (file)
conditions.lisp (file)
Return a list of handlers attached to HOOK.
protocol.lisp (file)
(setf hook-handlers) (generic function)
object-internal.lisp (file)
symbol.lisp (file)
The list of handlers associated with this hook.
mixins.lisp (file)
Replace list of handlers attached to HOOK with NEW-VALUE.
protocol.lisp (file)
hook-handlers (generic function)
The list of handlers associated with this hook.
mixins.lisp (file)
Check whether HOOK becomes active or inactive.
state.lisp (file)
Return the name of HOOK (a symbol).
protocol.lisp (file)
The name of this hook.
object-external.lisp (file)
The slot in which the hook resides.
object-internal.lisp (file)
symbol.lisp (file)
The object in which the hook resides.
object-internal.lisp (file)
conditions.lisp (file)
Return a representation of the slot residing in OBJECT under the name HOOK.
object-internal.lisp (file)
Called when HOOK becomes active.
state.lisp (file)
If HOOK has a handler for becoming active installed, call that handler.
mixins.lisp (file)
Default behavior is to do nothing.
Called when HOOK becomes inactive.
state.lisp (file)
If HOOK has a handler for becoming inactive installed, call that handler.
mixins.lisp (file)
Default behavior is to do nothing.
Remove HANDLER from HOOK.
protocol.lisp (file)
hook.lisp (file)
Run HOOK passing extra args ARGS to all handlers.
protocol.lisp (file)
hook.lisp (file)
Next: Exported classes, Previous: Exported generic functions, Up: Exported definitions [Contents][Index]
This condition is signaled if a handler is added to a hook to which it has been added before and the policy does not permit handlers to be added to a hook multiple times.
conditions.lisp (file)
hook-error-mixin (condition)
hook-error-handler (method)
The handler which was added to the hook twice.
:handler
hook-error-handler (generic function)
Initarg | Value |
---|---|
:handler | (alexandria:required-argument :handler) |
This condition servers as a superclass for condition classes that are related to hooks.
conditions.lisp (file)
error (condition)
hook-error-hook (method)
The hook object from which the error originated.
:hook
hook-error-hook (generic function)
Initarg | Value |
---|---|
:hook | (alexandria:required-argument :hook) |
This condition is signaled if an invalid hook-handler binding is detected during the expansion of an ‘with-handlers’ macro.
conditions.lisp (file)
error (condition)
malformed-handler-binding-binding (method)
The invalid hook-handler binding.
:binding
malformed-handler-binding-binding (generic function)
Initarg | Value |
---|---|
:binding | (alexandria:required-argument :binding) |
This condition is signaled when a designated hook cannot be found.
conditions.lisp (file)
hook-error-mixin (condition)
Previous: Exported conditions, Up: Exported definitions [Contents][Index]
Instances of this class represent hooks that reside outside of objects.
object-external.lisp (file)
hook-name (method)
The name of this hook.
symbol
:name
hook-name (generic function)
Initarg | Value |
---|---|
:name | (alexandria:required-argument :name) |
Instances of this class represent hooks that reside in object.
object-internal.lisp (file)
The object in which the hook resides.
standard-object
:object
hook-object (generic function)
The slot in which the hook resides.
symbol
:slot
hook-name (generic function)
Initarg | Value |
---|---|
:object | (alexandria:required-argument :object) |
:slot | (alexandria:required-argument :slot) |
Previous: Exported definitions, Up: Definitions [Contents][Index]
• Internal functions | ||
• Internal classes |
Next: Internal classes, Previous: Internal definitions, Up: Internal definitions [Contents][Index]
Run HANDLER with ARGS.
Signal CONDITION with appropriate restarts installed.
The installed restarts for HANDLER are:
+ ‘retry’
+ ‘continue’
+ ‘use-value’
The installed restarts for HOOK are:
+ ‘retry’
+ ‘use-value’
Previous: Internal functions, Up: Internal definitions [Contents][Index]
This mixin adds slot to functions which run when the hook becomes active or inactive.
mixins.lisp (file)
standard-object (class)
If a function is stored in this slot, the function is called when the hook becomes active.
(or null function)
hooks:on-become-active
If a function is stored in this slot, the function is called when the hook becomes inactive.
(or null function)
hooks:on-become-inactive
This mixin adds a slot which stores the hook combination of the hook.
mixins.lisp (file)
standard-object (class)
The hook combination used by this hook.
:combination
(quote progn)
hook-combination (generic function)
(setf hook-combination) (generic function)
This mixin adds a slot which stores the documentation of the hook.
mixins.lisp (file)
standard-object (class)
external-hook (class)
Documentation string of the hook.
(or null string)
:documentation
This mixin adds a slot which stores the list of handlers of the hook.
mixins.lisp (file)
standard-object (class)
external-hook (class)
The list of handlers associated with this hook.
list
:handlers
(quote nil)
hook-handlers (generic function)
(setf hook-handlers) (generic function)
This mixin adds simple printing behavior for hooks.
mixins.lisp (file)
standard-object (class)
print-object (method)
Previous: Definitions, Up: Top [Contents][Index]
• Concept index | ||
• Function index | ||
• Variable index | ||
• Data type index |
Next: Function index, Previous: Indexes, Up: Indexes [Contents][Index]
Jump to: | C F L M |
---|
Jump to: | C F L M |
---|
Next: Variable index, Previous: Concept index, Up: Indexes [Contents][Index]
Jump to: | (
A C D E F G H M O R S W |
---|
Jump to: | (
A C D E F G H M O R S W |
---|
Next: Data type index, Previous: Function index, Up: Indexes [Contents][Index]
Jump to: | B C D H N O S |
---|
Jump to: | B C D H N O S |
---|
Previous: Variable index, Up: Indexes [Contents][Index]
Jump to: | A C D E H I M N O P S |
---|
Jump to: | A C D E H I M N O P S |
---|