[Zope-PTK] Hooks
Dan L. Pierson
dan@sol.control.com
Mon, 21 Aug 2000 10:22:49 -0400 (EDT)
Shane Hathaway writes:
> Fabio Forno wrote:
> >
> > Perhaps it's a crazy idea, but what about a fully configurable hook map,
> > so that we allow the users to add the hook they want?
>
> An interesting idea. The one concern I have is that users really won't
> care about writing hooks for most things. For any sufficiently sizable
> change, users will want to write subclasses, not hook implementations.
> If you can develop an argument against that, I see no reason why we
> shouldn't write a generalized "hookable tool generator" that does all
> the work for us.
Seems like you're starting to reinvent a Lisp advice system. This is
an interface for wrapping a function or method in a new function such
that all calls will automagically go through the wrapper.
The docs for a simple version that's part of GNU Emacs are at the end
of this message. A Python interface might look like:
def advise(func, context, where, body, doc = None):
""" Wrap function 'func' so that 'body' is executed in the
relationship to func specified by 'where'. 'context' is the class or
module that func is part of (i.e. context.__dict__ will be modified to
accomplish this wrapping). 'where' can be one of: ADVISE_BEFORE,
ADVISE_AFTER, ADVISE_AROUND. The advised function will be available
as 'self.__advised__' and the next advice wrapper to be called will be
available as 'self.__advise_next__' (if there is no inner advice
wrapper, self.__advised__ and self.__advise_next__ will be the same).
'body' is a string that will be used to construct the real definition
of func. 'doc' is an optional doc string for func. """
# Implementation left as an exercise for the reader :-)
I think that the main pain in implementing this is likely to be that
body has to be a string because there's nothing like Lisp macros in
Python. On the other hand, this shouldn't be too hard with triple
quoted strings.
Here's the bit of Emacs Lisp doc I threatened you with earlier:
`defadvice' is a compiled Lisp macro
-- loaded from "advice"
Documentation:
Defines a piece of advice for FUNCTION (a symbol).
The syntax of `defadvice' is as follows:
(defadvice FUNCTION (CLASS NAME [POSITION] [ARGLIST] FLAG...)
[DOCSTRING] [INTERACTIVE-FORM]
BODY... )
FUNCTION ::= Name of the function to be advised.
CLASS ::= `before' | `around' | `after' | `activation' | `deactivation'.
NAME ::= Non-nil symbol that names this piece of advice.
POSITION ::= `first' | `last' | NUMBER. Optional, defaults to `first',
see also `ad-add-advice'.
ARGLIST ::= An optional argument list to be used for the advised function
instead of the argument list of the original. The first one found in
before/around/after-advices will be used.
FLAG ::= `protect'|`disable'|`activate'|`compile'|`preactivate'|`freeze'.
All flags can be specified with unambiguous initial substrings.
DOCSTRING ::= Optional documentation for this piece of advice.
INTERACTIVE-FORM ::= Optional interactive form to be used for the advised
function. The first one found in before/around/after-advices will be used.
BODY ::= Any s-expression.
Semantics of the various flags:
`protect': The piece of advice will be protected against non-local exits in
any code that precedes it. If any around-advice of a function is protected
then automatically all around-advices will be protected (the complete onion).
`activate': All advice of FUNCTION will be activated immediately if
FUNCTION has been properly defined prior to this application of `defadvice'.
`compile': In conjunction with `activate' specifies that the resulting
advised function should be compiled.
`disable': The defined advice will be disabled, hence, it will not be used
during activation until somebody enables it.
`preactivate': Preactivates the advised FUNCTION at macro-expansion/compile
time. This generates a compiled advised definition according to the current
advice state that will be used during activation if appropriate. Only use
this if the `defadvice' gets actually compiled.
`freeze': Expands the `defadvice' into a redefining `defun/defmacro' according
to this particular single advice. No other advice information will be saved.
Frozen advices cannot be undone, they behave like a hard redefinition of
the advised function. `freeze' implies `activate' and `preactivate'. The
documentation of the advised function can be dumped onto the `DOC' file
during preloading.
Look at the file `advice.el' for comprehensive documentation.