##// 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 # registrar.py - utilities to register function for specific purpose
1 # registrar.py - utilities to register function for specific purpose
2 #
2 #
3 # Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others
3 # Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from . import (
10 from . import (
11 util,
11 util,
12 )
12 )
13
13
14 class funcregistrar(object):
14 class funcregistrar(object):
15 """Base of decorator to register a fuction for specific purpose
15 """Base of decorator to register a fuction for specific purpose
16
16
17 The least derived class can be defined by overriding 'table' and
17 The least derived class can be defined by overriding 'table' and
18 'formatdoc', for example::
18 'formatdoc', for example::
19
19
20 symbols = {}
20 symbols = {}
21 class keyword(funcregistrar):
21 class keyword(funcregistrar):
22 table = symbols
22 table = symbols
23 formatdoc = ":%s: %s"
23 formatdoc = ":%s: %s"
24
24
25 @keyword('bar')
25 @keyword('bar')
26 def barfunc(*args, **kwargs):
26 def barfunc(*args, **kwargs):
27 '''Explanation of bar keyword ....
27 '''Explanation of bar keyword ....
28 '''
28 '''
29 pass
29 pass
30
30
31 In this case:
31 In this case:
32
32
33 - 'barfunc' is registered as 'bar' in 'symbols'
33 - 'barfunc' is registered as 'bar' in 'symbols'
34 - online help uses ":bar: Explanation of bar keyword"
34 - online help uses ":bar: Explanation of bar keyword"
35 """
35 """
36
36
37 def __init__(self, decl):
37 def __init__(self, decl):
38 """'decl' is a name or more descriptive string of a function
38 """'decl' is a name or more descriptive string of a function
39
39
40 Specification of 'decl' depends on registration purpose.
40 Specification of 'decl' depends on registration purpose.
41 """
41 """
42 self.decl = decl
42 self.decl = decl
43
43
44 table = None
44 table = None
45
45
46 def __call__(self, func):
46 def __call__(self, func):
47 """Execute actual registration for specified function
47 """Execute actual registration for specified function
48 """
48 """
49 name = self.getname()
49 name = self.getname()
50
50
51 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
51 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
52 doc = func.__doc__.strip()
52 doc = func.__doc__.strip()
53 func._origdoc = doc
53 func._origdoc = doc
54 if callable(self.formatdoc):
54 if callable(self.formatdoc):
55 func.__doc__ = self.formatdoc(doc)
55 func.__doc__ = self.formatdoc(doc)
56 else:
56 else:
57 # convenient shortcut for simple format
57 # convenient shortcut for simple format
58 func.__doc__ = self.formatdoc % (self.decl, doc)
58 func.__doc__ = self.formatdoc % (self.decl, doc)
59
59
60 self.table[name] = func
60 self.table[name] = func
61 self.extraaction(name, func)
61 self.extraaction(name, func)
62
62
63 return func
63 return func
64
64
65 def getname(self):
65 def getname(self):
66 """Return the name of the registered function from self.decl
66 """Return the name of the registered function from self.decl
67
67
68 Derived class should override this, if it allows more
68 Derived class should override this, if it allows more
69 descriptive 'decl' string than just a name.
69 descriptive 'decl' string than just a name.
70 """
70 """
71 return self.decl
71 return self.decl
72
72
73 def parsefuncdecl(self):
73 def parsefuncdecl(self):
74 """Parse function declaration and return the name of function in it
74 """Parse function declaration and return the name of function in it
75 """
75 """
76 i = self.decl.find('(')
76 i = self.decl.find('(')
77 if i > 0:
77 if i > 0:
78 return self.decl[:i]
78 return self.decl[:i]
79 else:
79 else:
80 return self.decl
80 return self.decl
81
81
82 def formatdoc(self, doc):
82 def formatdoc(self, doc):
83 """Return formatted document of the registered function for help
83 """Return formatted document of the registered function for help
84
84
85 'doc' is '__doc__.strip()' of the registered function.
85 'doc' is '__doc__.strip()' of the registered function.
86
86
87 If this is overridden by non-callable object in derived class,
87 If this is overridden by non-callable object in derived class,
88 such value is treated as "format string" and used to format
88 such value is treated as "format string" and used to format
89 document by 'self.formatdoc % (self.decl, doc)' for convenience.
89 document by 'self.formatdoc % (self.decl, doc)' for convenience.
90 """
90 """
91 raise NotImplementedError()
91 raise NotImplementedError()
92
92
93 def extraaction(self, name, func):
93 def extraaction(self, name, func):
94 """Execute exra action for registered function, if needed
94 """Execute exra action for registered function, if needed
95 """
95 """
96 pass
96 pass
97
97
98 class delayregistrar(object):
98 class delayregistrar(object):
99 """Decorator to delay actual registration until uisetup or so
99 """Decorator to delay actual registration until uisetup or so
100
100
101 For example, the decorator class to delay registration by
101 For example, the decorator class to delay registration by
102 'keyword' funcregistrar can be defined as below::
102 'keyword' funcregistrar can be defined as below::
103
103
104 class extkeyword(delayregistrar):
104 class extkeyword(delayregistrar):
105 registrar = keyword
105 registrar = keyword
106 """
106 """
107 def __init__(self):
107 def __init__(self):
108 self._list = []
108 self._list = []
109
109
110 registrar = None
110 registrar = None
111
111
112 def __call__(self, *args, **kwargs):
112 def __call__(self, *args, **kwargs):
113 """Return the decorator to delay actual registration until setup
113 """Return the decorator to delay actual registration until setup
114 """
114 """
115 assert self.registrar is not None
115 assert self.registrar is not None
116 def decorator(func):
116 def decorator(func):
117 # invocation of self.registrar() here can detect argument
117 # invocation of self.registrar() here can detect argument
118 # mismatching immediately
118 # mismatching immediately
119 self._list.append((func, self.registrar(*args, **kwargs)))
119 self._list.append((func, self.registrar(*args, **kwargs)))
120 return func
120 return func
121 return decorator
121 return decorator
122
122
123 def setup(self):
123 def setup(self):
124 """Execute actual registration
124 """Execute actual registration
125 """
125 """
126 while self._list:
126 while self._list:
127 func, decorator = self._list.pop(0)
127 func, decorator = self._list.pop(0)
128 decorator(func)
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