##// END OF EJS Templates
registrar: introduce new class for registration to replace funcregistrar...
FUJIWARA Katsunori -
r28392:b983a2f0 default
parent child Browse files
Show More
@@ -1,128 +1,207 b''
1 1 # registrar.py - utilities to register function for specific purpose
2 2 #
3 3 # Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 from . import (
11 11 util,
12 12 )
13 13
14 14 class funcregistrar(object):
15 15 """Base of decorator to register a fuction for specific purpose
16 16
17 17 The least derived class can be defined by overriding 'table' and
18 18 'formatdoc', for example::
19 19
20 20 symbols = {}
21 21 class keyword(funcregistrar):
22 22 table = symbols
23 23 formatdoc = ":%s: %s"
24 24
25 25 @keyword('bar')
26 26 def barfunc(*args, **kwargs):
27 27 '''Explanation of bar keyword ....
28 28 '''
29 29 pass
30 30
31 31 In this case:
32 32
33 33 - 'barfunc' is registered as 'bar' in 'symbols'
34 34 - online help uses ":bar: Explanation of bar keyword"
35 35 """
36 36
37 37 def __init__(self, decl):
38 38 """'decl' is a name or more descriptive string of a function
39 39
40 40 Specification of 'decl' depends on registration purpose.
41 41 """
42 42 self.decl = decl
43 43
44 44 table = None
45 45
46 46 def __call__(self, func):
47 47 """Execute actual registration for specified function
48 48 """
49 49 name = self.getname()
50 50
51 51 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
52 52 doc = func.__doc__.strip()
53 53 func._origdoc = doc
54 54 if callable(self.formatdoc):
55 55 func.__doc__ = self.formatdoc(doc)
56 56 else:
57 57 # convenient shortcut for simple format
58 58 func.__doc__ = self.formatdoc % (self.decl, doc)
59 59
60 60 self.table[name] = func
61 61 self.extraaction(name, func)
62 62
63 63 return func
64 64
65 65 def getname(self):
66 66 """Return the name of the registered function from self.decl
67 67
68 68 Derived class should override this, if it allows more
69 69 descriptive 'decl' string than just a name.
70 70 """
71 71 return self.decl
72 72
73 73 def parsefuncdecl(self):
74 74 """Parse function declaration and return the name of function in it
75 75 """
76 76 i = self.decl.find('(')
77 77 if i > 0:
78 78 return self.decl[:i]
79 79 else:
80 80 return self.decl
81 81
82 82 def formatdoc(self, doc):
83 83 """Return formatted document of the registered function for help
84 84
85 85 'doc' is '__doc__.strip()' of the registered function.
86 86
87 87 If this is overridden by non-callable object in derived class,
88 88 such value is treated as "format string" and used to format
89 89 document by 'self.formatdoc % (self.decl, doc)' for convenience.
90 90 """
91 91 raise NotImplementedError()
92 92
93 93 def extraaction(self, name, func):
94 94 """Execute exra action for registered function, if needed
95 95 """
96 96 pass
97 97
98 98 class delayregistrar(object):
99 99 """Decorator to delay actual registration until uisetup or so
100 100
101 101 For example, the decorator class to delay registration by
102 102 'keyword' funcregistrar can be defined as below::
103 103
104 104 class extkeyword(delayregistrar):
105 105 registrar = keyword
106 106 """
107 107 def __init__(self):
108 108 self._list = []
109 109
110 110 registrar = None
111 111
112 112 def __call__(self, *args, **kwargs):
113 113 """Return the decorator to delay actual registration until setup
114 114 """
115 115 assert self.registrar is not None
116 116 def decorator(func):
117 117 # invocation of self.registrar() here can detect argument
118 118 # mismatching immediately
119 119 self._list.append((func, self.registrar(*args, **kwargs)))
120 120 return func
121 121 return decorator
122 122
123 123 def setup(self):
124 124 """Execute actual registration
125 125 """
126 126 while self._list:
127 127 func, decorator = self._list.pop(0)
128 128 decorator(func)
129
130 class _funcregistrarbase(object):
131 """Base of decorator to register a fuction for specific purpose
132
133 This decorator stores decorated functions into own dict 'table'.
134
135 The least derived class can be defined by overriding 'formatdoc',
136 for example::
137
138 class keyword(_funcregistrarbase):
139 _docformat = ":%s: %s"
140
141 This should be used as below:
142
143 keyword = registrar.keyword()
144
145 @keyword('bar')
146 def barfunc(*args, **kwargs):
147 '''Explanation of bar keyword ....
148 '''
149 pass
150
151 In this case:
152
153 - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above
154 - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword"
155 """
156 def __init__(self, table=None):
157 if table is None:
158 self._table = {}
159 else:
160 self._table = table
161
162 def __call__(self, decl, *args, **kwargs):
163 return lambda func: self._doregister(func, decl, *args, **kwargs)
164
165 def _doregister(self, func, decl, *args, **kwargs):
166 name = self._getname(decl)
167
168 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
169 doc = func.__doc__.strip()
170 func._origdoc = doc
171 func.__doc__ = self._formatdoc(decl, doc)
172
173 self._table[name] = func
174 self._extrasetup(name, func, *args, **kwargs)
175
176 return func
177
178 def _parsefuncdecl(self, decl):
179 """Parse function declaration and return the name of function in it
180 """
181 i = decl.find('(')
182 if i >= 0:
183 return decl[:i]
184 else:
185 return decl
186
187 def _getname(self, decl):
188 """Return the name of the registered function from decl
189
190 Derived class should override this, if it allows more
191 descriptive 'decl' string than just a name.
192 """
193 return decl
194
195 _docformat = None
196
197 def _formatdoc(self, decl, doc):
198 """Return formatted document of the registered function for help
199
200 'doc' is '__doc__.strip()' of the registered function.
201 """
202 return self._docformat % (decl, doc)
203
204 def _extrasetup(self, name, func):
205 """Execute exra setup for registered function, if needed
206 """
207 pass
General Comments 0
You need to be logged in to leave comments. Login now