registrar.py
128 lines
| 3.7 KiB
| text/x-python
|
PythonLexer
/ mercurial / registrar.py
FUJIWARA Katsunori
|
r27583 | # registrar.py - utilities to register function for specific purpose | ||
# | ||||
# Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
from __future__ import absolute_import | ||||
from . import ( | ||||
util, | ||||
) | ||||
class funcregistrar(object): | ||||
"""Base of decorator to register a fuction for specific purpose | ||||
The least derived class can be defined by overriding 'table' and | ||||
'formatdoc', for example:: | ||||
symbols = {} | ||||
class keyword(funcregistrar): | ||||
table = symbols | ||||
formatdoc = ":%s: %s" | ||||
@keyword('bar') | ||||
def barfunc(*args, **kwargs): | ||||
'''Explanation of bar keyword .... | ||||
''' | ||||
pass | ||||
In this case: | ||||
- 'barfunc' is registered as 'bar' in 'symbols' | ||||
- online help uses ":bar: Explanation of bar keyword" | ||||
""" | ||||
def __init__(self, decl): | ||||
"""'decl' is a name or more descriptive string of a function | ||||
Specification of 'decl' depends on registration purpose. | ||||
""" | ||||
self.decl = decl | ||||
table = None | ||||
def __call__(self, func): | ||||
"""Execute actual registration for specified function | ||||
""" | ||||
name = self.getname() | ||||
if func.__doc__ and not util.safehasattr(func, '_origdoc'): | ||||
doc = func.__doc__.strip() | ||||
func._origdoc = doc | ||||
if callable(self.formatdoc): | ||||
func.__doc__ = self.formatdoc(doc) | ||||
else: | ||||
# convenient shortcut for simple format | ||||
func.__doc__ = self.formatdoc % (self.decl, doc) | ||||
self.table[name] = func | ||||
self.extraaction(name, func) | ||||
return func | ||||
def getname(self): | ||||
"""Return the name of the registered function from self.decl | ||||
Derived class should override this, if it allows more | ||||
descriptive 'decl' string than just a name. | ||||
""" | ||||
return self.decl | ||||
FUJIWARA Katsunori
|
r27584 | def parsefuncdecl(self): | ||
"""Parse function declaration and return the name of function in it | ||||
""" | ||||
i = self.decl.find('(') | ||||
if i > 0: | ||||
return self.decl[:i] | ||||
else: | ||||
return self.decl | ||||
FUJIWARA Katsunori
|
r27583 | def formatdoc(self, doc): | ||
"""Return formatted document of the registered function for help | ||||
'doc' is '__doc__.strip()' of the registered function. | ||||
If this is overridden by non-callable object in derived class, | ||||
such value is treated as "format string" and used to format | ||||
document by 'self.formatdoc % (self.decl, doc)' for convenience. | ||||
""" | ||||
raise NotImplementedError() | ||||
def extraaction(self, name, func): | ||||
"""Execute exra action for registered function, if needed | ||||
""" | ||||
pass | ||||
FUJIWARA Katsunori
|
r27585 | |||
class delayregistrar(object): | ||||
"""Decorator to delay actual registration until uisetup or so | ||||
For example, the decorator class to delay registration by | ||||
'keyword' funcregistrar can be defined as below:: | ||||
class extkeyword(delayregistrar): | ||||
registrar = keyword | ||||
""" | ||||
def __init__(self): | ||||
self._list = [] | ||||
registrar = None | ||||
def __call__(self, *args, **kwargs): | ||||
"""Return the decorator to delay actual registration until setup | ||||
""" | ||||
assert self.registrar is not None | ||||
def decorator(func): | ||||
# invocation of self.registrar() here can detect argument | ||||
# mismatching immediately | ||||
self._list.append((func, self.registrar(*args, **kwargs))) | ||||
return func | ||||
return decorator | ||||
def setup(self): | ||||
"""Execute actual registration | ||||
""" | ||||
while self._list: | ||||
func, decorator = self._list.pop(0) | ||||
decorator(func) | ||||