##// END OF EJS Templates
registrar: switch @command decorator to class...
Yuya Nishihara -
r32338:ec84db23 default
parent child Browse files
Show More
@@ -1,306 +1,303 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 error,
12 12 pycompat,
13 13 util,
14 14 )
15 15
16 16 class _funcregistrarbase(object):
17 17 """Base of decorator to register a function for specific purpose
18 18
19 19 This decorator stores decorated functions into own dict 'table'.
20 20
21 21 The least derived class can be defined by overriding 'formatdoc',
22 22 for example::
23 23
24 24 class keyword(_funcregistrarbase):
25 25 _docformat = ":%s: %s"
26 26
27 27 This should be used as below:
28 28
29 29 keyword = registrar.keyword()
30 30
31 31 @keyword('bar')
32 32 def barfunc(*args, **kwargs):
33 33 '''Explanation of bar keyword ....
34 34 '''
35 35 pass
36 36
37 37 In this case:
38 38
39 39 - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above
40 40 - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword"
41 41 """
42 42 def __init__(self, table=None):
43 43 if table is None:
44 44 self._table = {}
45 45 else:
46 46 self._table = table
47 47
48 48 def __call__(self, decl, *args, **kwargs):
49 49 return lambda func: self._doregister(func, decl, *args, **kwargs)
50 50
51 51 def _doregister(self, func, decl, *args, **kwargs):
52 52 name = self._getname(decl)
53 53
54 54 if name in self._table:
55 55 msg = 'duplicate registration for name: "%s"' % name
56 56 raise error.ProgrammingError(msg)
57 57
58 58 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
59 59 doc = pycompat.sysbytes(func.__doc__).strip()
60 60 func._origdoc = doc
61 61 func.__doc__ = pycompat.sysstr(self._formatdoc(decl, doc))
62 62
63 63 self._table[name] = func
64 64 self._extrasetup(name, func, *args, **kwargs)
65 65
66 66 return func
67 67
68 68 def _parsefuncdecl(self, decl):
69 69 """Parse function declaration and return the name of function in it
70 70 """
71 71 i = decl.find('(')
72 72 if i >= 0:
73 73 return decl[:i]
74 74 else:
75 75 return decl
76 76
77 77 def _getname(self, decl):
78 78 """Return the name of the registered function from decl
79 79
80 80 Derived class should override this, if it allows more
81 81 descriptive 'decl' string than just a name.
82 82 """
83 83 return decl
84 84
85 85 _docformat = None
86 86
87 87 def _formatdoc(self, decl, doc):
88 88 """Return formatted document of the registered function for help
89 89
90 90 'doc' is '__doc__.strip()' of the registered function.
91 91 """
92 92 return self._docformat % (decl, doc)
93 93
94 94 def _extrasetup(self, name, func):
95 95 """Execute exra setup for registered function, if needed
96 96 """
97 97 pass
98 98
99 def command(table):
100 """Returns a function object to be used as a decorator for making commands.
99 class command(_funcregistrarbase):
100 """Decorator to register a command function to table
101 101
102 This function receives a command table as its argument. The table should
102 This class receives a command table as its argument. The table should
103 103 be a dict.
104 104
105 The returned function can be used as a decorator for adding commands
106 to that command table. This function accepts multiple arguments to define
107 a command.
105 The created object can be used as a decorator for adding commands to
106 that command table. This accepts multiple arguments to define a command.
108 107
109 108 The first argument is the command name.
110 109
111 110 The options argument is an iterable of tuples defining command arguments.
112 111 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
113 112
114 113 The synopsis argument defines a short, one line summary of how to use the
115 114 command. This shows up in the help output.
116 115
117 116 The norepo argument defines whether the command does not require a
118 117 local repository. Most commands operate against a repository, thus the
119 118 default is False.
120 119
121 120 The optionalrepo argument defines whether the command optionally requires
122 121 a local repository.
123 122
124 123 The inferrepo argument defines whether to try to find a repository from the
125 124 command line arguments. If True, arguments will be examined for potential
126 125 repository locations. See ``findrepo()``. If a repository is found, it
127 126 will be used.
128 127 """
129 def cmd(name, options=(), synopsis=None, norepo=False, optionalrepo=False,
130 inferrepo=False):
131 def decorator(func):
128
129 def _doregister(self, func, name, options=(), synopsis=None,
130 norepo=False, optionalrepo=False, inferrepo=False):
131 if True:
132 132 func.norepo = norepo
133 133 func.optionalrepo = optionalrepo
134 134 func.inferrepo = inferrepo
135 135 if synopsis:
136 table[name] = func, list(options), synopsis
136 self._table[name] = func, list(options), synopsis
137 137 else:
138 table[name] = func, list(options)
138 self._table[name] = func, list(options)
139 139 return func
140 return decorator
141
142 return cmd
143 140
144 141 class revsetpredicate(_funcregistrarbase):
145 142 """Decorator to register revset predicate
146 143
147 144 Usage::
148 145
149 146 revsetpredicate = registrar.revsetpredicate()
150 147
151 148 @revsetpredicate('mypredicate(arg1, arg2[, arg3])')
152 149 def mypredicatefunc(repo, subset, x):
153 150 '''Explanation of this revset predicate ....
154 151 '''
155 152 pass
156 153
157 154 The first string argument is used also in online help.
158 155
159 156 Optional argument 'safe' indicates whether a predicate is safe for
160 157 DoS attack (False by default).
161 158
162 159 Optional argument 'takeorder' indicates whether a predicate function
163 160 takes ordering policy as the last argument.
164 161
165 162 'revsetpredicate' instance in example above can be used to
166 163 decorate multiple functions.
167 164
168 165 Decorated functions are registered automatically at loading
169 166 extension, if an instance named as 'revsetpredicate' is used for
170 167 decorating in extension.
171 168
172 169 Otherwise, explicit 'revset.loadpredicate()' is needed.
173 170 """
174 171 _getname = _funcregistrarbase._parsefuncdecl
175 172 _docformat = "``%s``\n %s"
176 173
177 174 def _extrasetup(self, name, func, safe=False, takeorder=False):
178 175 func._safe = safe
179 176 func._takeorder = takeorder
180 177
181 178 class filesetpredicate(_funcregistrarbase):
182 179 """Decorator to register fileset predicate
183 180
184 181 Usage::
185 182
186 183 filesetpredicate = registrar.filesetpredicate()
187 184
188 185 @filesetpredicate('mypredicate()')
189 186 def mypredicatefunc(mctx, x):
190 187 '''Explanation of this fileset predicate ....
191 188 '''
192 189 pass
193 190
194 191 The first string argument is used also in online help.
195 192
196 193 Optional argument 'callstatus' indicates whether a predicate
197 194 implies 'matchctx.status()' at runtime or not (False, by
198 195 default).
199 196
200 197 Optional argument 'callexisting' indicates whether a predicate
201 198 implies 'matchctx.existing()' at runtime or not (False, by
202 199 default).
203 200
204 201 'filesetpredicate' instance in example above can be used to
205 202 decorate multiple functions.
206 203
207 204 Decorated functions are registered automatically at loading
208 205 extension, if an instance named as 'filesetpredicate' is used for
209 206 decorating in extension.
210 207
211 208 Otherwise, explicit 'fileset.loadpredicate()' is needed.
212 209 """
213 210 _getname = _funcregistrarbase._parsefuncdecl
214 211 _docformat = "``%s``\n %s"
215 212
216 213 def _extrasetup(self, name, func, callstatus=False, callexisting=False):
217 214 func._callstatus = callstatus
218 215 func._callexisting = callexisting
219 216
220 217 class _templateregistrarbase(_funcregistrarbase):
221 218 """Base of decorator to register functions as template specific one
222 219 """
223 220 _docformat = ":%s: %s"
224 221
225 222 class templatekeyword(_templateregistrarbase):
226 223 """Decorator to register template keyword
227 224
228 225 Usage::
229 226
230 227 templatekeyword = registrar.templatekeyword()
231 228
232 229 @templatekeyword('mykeyword')
233 230 def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
234 231 '''Explanation of this template keyword ....
235 232 '''
236 233 pass
237 234
238 235 The first string argument is used also in online help.
239 236
240 237 'templatekeyword' instance in example above can be used to
241 238 decorate multiple functions.
242 239
243 240 Decorated functions are registered automatically at loading
244 241 extension, if an instance named as 'templatekeyword' is used for
245 242 decorating in extension.
246 243
247 244 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
248 245 """
249 246
250 247 class templatefilter(_templateregistrarbase):
251 248 """Decorator to register template filer
252 249
253 250 Usage::
254 251
255 252 templatefilter = registrar.templatefilter()
256 253
257 254 @templatefilter('myfilter')
258 255 def myfilterfunc(text):
259 256 '''Explanation of this template filter ....
260 257 '''
261 258 pass
262 259
263 260 The first string argument is used also in online help.
264 261
265 262 'templatefilter' instance in example above can be used to
266 263 decorate multiple functions.
267 264
268 265 Decorated functions are registered automatically at loading
269 266 extension, if an instance named as 'templatefilter' is used for
270 267 decorating in extension.
271 268
272 269 Otherwise, explicit 'templatefilters.loadkeyword()' is needed.
273 270 """
274 271
275 272 class templatefunc(_templateregistrarbase):
276 273 """Decorator to register template function
277 274
278 275 Usage::
279 276
280 277 templatefunc = registrar.templatefunc()
281 278
282 279 @templatefunc('myfunc(arg1, arg2[, arg3])', argspec='arg1 arg2 arg3')
283 280 def myfuncfunc(context, mapping, args):
284 281 '''Explanation of this template function ....
285 282 '''
286 283 pass
287 284
288 285 The first string argument is used also in online help.
289 286
290 287 If optional 'argspec' is defined, the function will receive 'args' as
291 288 a dict of named arguments. Otherwise 'args' is a list of positional
292 289 arguments.
293 290
294 291 'templatefunc' instance in example above can be used to
295 292 decorate multiple functions.
296 293
297 294 Decorated functions are registered automatically at loading
298 295 extension, if an instance named as 'templatefunc' is used for
299 296 decorating in extension.
300 297
301 298 Otherwise, explicit 'templater.loadfunction()' is needed.
302 299 """
303 300 _getname = _funcregistrarbase._parsefuncdecl
304 301
305 302 def _extrasetup(self, name, func, argspec=None):
306 303 func._argspec = argspec
General Comments 0
You need to be logged in to leave comments. Login now