##// END OF EJS Templates
registrar: raise a programming error on duplicated registering...
Pierre-Yves David -
r30608:b52e8a4f default
parent child Browse files
Show More
@@ -1,249 +1,254 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 error,
11 pycompat,
12 pycompat,
12 util,
13 util,
13 )
14 )
14
15
15 class _funcregistrarbase(object):
16 class _funcregistrarbase(object):
16 """Base of decorator to register a function for specific purpose
17 """Base of decorator to register a function for specific purpose
17
18
18 This decorator stores decorated functions into own dict 'table'.
19 This decorator stores decorated functions into own dict 'table'.
19
20
20 The least derived class can be defined by overriding 'formatdoc',
21 The least derived class can be defined by overriding 'formatdoc',
21 for example::
22 for example::
22
23
23 class keyword(_funcregistrarbase):
24 class keyword(_funcregistrarbase):
24 _docformat = ":%s: %s"
25 _docformat = ":%s: %s"
25
26
26 This should be used as below:
27 This should be used as below:
27
28
28 keyword = registrar.keyword()
29 keyword = registrar.keyword()
29
30
30 @keyword('bar')
31 @keyword('bar')
31 def barfunc(*args, **kwargs):
32 def barfunc(*args, **kwargs):
32 '''Explanation of bar keyword ....
33 '''Explanation of bar keyword ....
33 '''
34 '''
34 pass
35 pass
35
36
36 In this case:
37 In this case:
37
38
38 - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above
39 - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above
39 - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword"
40 - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword"
40 """
41 """
41 def __init__(self, table=None):
42 def __init__(self, table=None):
42 if table is None:
43 if table is None:
43 self._table = {}
44 self._table = {}
44 else:
45 else:
45 self._table = table
46 self._table = table
46
47
47 def __call__(self, decl, *args, **kwargs):
48 def __call__(self, decl, *args, **kwargs):
48 return lambda func: self._doregister(func, decl, *args, **kwargs)
49 return lambda func: self._doregister(func, decl, *args, **kwargs)
49
50
50 def _doregister(self, func, decl, *args, **kwargs):
51 def _doregister(self, func, decl, *args, **kwargs):
51 name = self._getname(decl)
52 name = self._getname(decl)
52
53
54 if name in self._table:
55 msg = 'duplicate registration for name: "%s"' % name
56 raise error.ProgrammingError(msg)
57
53 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
58 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
54 doc = func.__doc__.strip()
59 doc = func.__doc__.strip()
55 func._origdoc = doc
60 func._origdoc = doc
56 func.__doc__ = self._formatdoc(decl, doc)
61 func.__doc__ = self._formatdoc(decl, doc)
57
62
58 self._table[name] = func
63 self._table[name] = func
59 self._extrasetup(name, func, *args, **kwargs)
64 self._extrasetup(name, func, *args, **kwargs)
60
65
61 return func
66 return func
62
67
63 def _parsefuncdecl(self, decl):
68 def _parsefuncdecl(self, decl):
64 """Parse function declaration and return the name of function in it
69 """Parse function declaration and return the name of function in it
65 """
70 """
66 i = decl.find('(')
71 i = decl.find('(')
67 if i >= 0:
72 if i >= 0:
68 return decl[:i]
73 return decl[:i]
69 else:
74 else:
70 return decl
75 return decl
71
76
72 def _getname(self, decl):
77 def _getname(self, decl):
73 """Return the name of the registered function from decl
78 """Return the name of the registered function from decl
74
79
75 Derived class should override this, if it allows more
80 Derived class should override this, if it allows more
76 descriptive 'decl' string than just a name.
81 descriptive 'decl' string than just a name.
77 """
82 """
78 return decl
83 return decl
79
84
80 _docformat = None
85 _docformat = None
81
86
82 def _formatdoc(self, decl, doc):
87 def _formatdoc(self, decl, doc):
83 """Return formatted document of the registered function for help
88 """Return formatted document of the registered function for help
84
89
85 'doc' is '__doc__.strip()' of the registered function.
90 'doc' is '__doc__.strip()' of the registered function.
86 """
91 """
87 return self._docformat % (decl, doc)
92 return self._docformat % (decl, doc)
88
93
89 def _extrasetup(self, name, func):
94 def _extrasetup(self, name, func):
90 """Execute exra setup for registered function, if needed
95 """Execute exra setup for registered function, if needed
91 """
96 """
92 pass
97 pass
93
98
94 class revsetpredicate(_funcregistrarbase):
99 class revsetpredicate(_funcregistrarbase):
95 """Decorator to register revset predicate
100 """Decorator to register revset predicate
96
101
97 Usage::
102 Usage::
98
103
99 revsetpredicate = registrar.revsetpredicate()
104 revsetpredicate = registrar.revsetpredicate()
100
105
101 @revsetpredicate('mypredicate(arg1, arg2[, arg3])')
106 @revsetpredicate('mypredicate(arg1, arg2[, arg3])')
102 def mypredicatefunc(repo, subset, x):
107 def mypredicatefunc(repo, subset, x):
103 '''Explanation of this revset predicate ....
108 '''Explanation of this revset predicate ....
104 '''
109 '''
105 pass
110 pass
106
111
107 The first string argument is used also in online help.
112 The first string argument is used also in online help.
108
113
109 Optional argument 'safe' indicates whether a predicate is safe for
114 Optional argument 'safe' indicates whether a predicate is safe for
110 DoS attack (False by default).
115 DoS attack (False by default).
111
116
112 Optional argument 'takeorder' indicates whether a predicate function
117 Optional argument 'takeorder' indicates whether a predicate function
113 takes ordering policy as the last argument.
118 takes ordering policy as the last argument.
114
119
115 'revsetpredicate' instance in example above can be used to
120 'revsetpredicate' instance in example above can be used to
116 decorate multiple functions.
121 decorate multiple functions.
117
122
118 Decorated functions are registered automatically at loading
123 Decorated functions are registered automatically at loading
119 extension, if an instance named as 'revsetpredicate' is used for
124 extension, if an instance named as 'revsetpredicate' is used for
120 decorating in extension.
125 decorating in extension.
121
126
122 Otherwise, explicit 'revset.loadpredicate()' is needed.
127 Otherwise, explicit 'revset.loadpredicate()' is needed.
123 """
128 """
124 _getname = _funcregistrarbase._parsefuncdecl
129 _getname = _funcregistrarbase._parsefuncdecl
125 _docformat = pycompat.sysstr("``%s``\n %s")
130 _docformat = pycompat.sysstr("``%s``\n %s")
126
131
127 def _extrasetup(self, name, func, safe=False, takeorder=False):
132 def _extrasetup(self, name, func, safe=False, takeorder=False):
128 func._safe = safe
133 func._safe = safe
129 func._takeorder = takeorder
134 func._takeorder = takeorder
130
135
131 class filesetpredicate(_funcregistrarbase):
136 class filesetpredicate(_funcregistrarbase):
132 """Decorator to register fileset predicate
137 """Decorator to register fileset predicate
133
138
134 Usage::
139 Usage::
135
140
136 filesetpredicate = registrar.filesetpredicate()
141 filesetpredicate = registrar.filesetpredicate()
137
142
138 @filesetpredicate('mypredicate()')
143 @filesetpredicate('mypredicate()')
139 def mypredicatefunc(mctx, x):
144 def mypredicatefunc(mctx, x):
140 '''Explanation of this fileset predicate ....
145 '''Explanation of this fileset predicate ....
141 '''
146 '''
142 pass
147 pass
143
148
144 The first string argument is used also in online help.
149 The first string argument is used also in online help.
145
150
146 Optional argument 'callstatus' indicates whether a predicate
151 Optional argument 'callstatus' indicates whether a predicate
147 implies 'matchctx.status()' at runtime or not (False, by
152 implies 'matchctx.status()' at runtime or not (False, by
148 default).
153 default).
149
154
150 Optional argument 'callexisting' indicates whether a predicate
155 Optional argument 'callexisting' indicates whether a predicate
151 implies 'matchctx.existing()' at runtime or not (False, by
156 implies 'matchctx.existing()' at runtime or not (False, by
152 default).
157 default).
153
158
154 'filesetpredicate' instance in example above can be used to
159 'filesetpredicate' instance in example above can be used to
155 decorate multiple functions.
160 decorate multiple functions.
156
161
157 Decorated functions are registered automatically at loading
162 Decorated functions are registered automatically at loading
158 extension, if an instance named as 'filesetpredicate' is used for
163 extension, if an instance named as 'filesetpredicate' is used for
159 decorating in extension.
164 decorating in extension.
160
165
161 Otherwise, explicit 'fileset.loadpredicate()' is needed.
166 Otherwise, explicit 'fileset.loadpredicate()' is needed.
162 """
167 """
163 _getname = _funcregistrarbase._parsefuncdecl
168 _getname = _funcregistrarbase._parsefuncdecl
164 _docformat = pycompat.sysstr("``%s``\n %s")
169 _docformat = pycompat.sysstr("``%s``\n %s")
165
170
166 def _extrasetup(self, name, func, callstatus=False, callexisting=False):
171 def _extrasetup(self, name, func, callstatus=False, callexisting=False):
167 func._callstatus = callstatus
172 func._callstatus = callstatus
168 func._callexisting = callexisting
173 func._callexisting = callexisting
169
174
170 class _templateregistrarbase(_funcregistrarbase):
175 class _templateregistrarbase(_funcregistrarbase):
171 """Base of decorator to register functions as template specific one
176 """Base of decorator to register functions as template specific one
172 """
177 """
173 _docformat = pycompat.sysstr(":%s: %s")
178 _docformat = pycompat.sysstr(":%s: %s")
174
179
175 class templatekeyword(_templateregistrarbase):
180 class templatekeyword(_templateregistrarbase):
176 """Decorator to register template keyword
181 """Decorator to register template keyword
177
182
178 Usage::
183 Usage::
179
184
180 templatekeyword = registrar.templatekeyword()
185 templatekeyword = registrar.templatekeyword()
181
186
182 @templatekeyword('mykeyword')
187 @templatekeyword('mykeyword')
183 def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
188 def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
184 '''Explanation of this template keyword ....
189 '''Explanation of this template keyword ....
185 '''
190 '''
186 pass
191 pass
187
192
188 The first string argument is used also in online help.
193 The first string argument is used also in online help.
189
194
190 'templatekeyword' instance in example above can be used to
195 'templatekeyword' instance in example above can be used to
191 decorate multiple functions.
196 decorate multiple functions.
192
197
193 Decorated functions are registered automatically at loading
198 Decorated functions are registered automatically at loading
194 extension, if an instance named as 'templatekeyword' is used for
199 extension, if an instance named as 'templatekeyword' is used for
195 decorating in extension.
200 decorating in extension.
196
201
197 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
202 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
198 """
203 """
199
204
200 class templatefilter(_templateregistrarbase):
205 class templatefilter(_templateregistrarbase):
201 """Decorator to register template filer
206 """Decorator to register template filer
202
207
203 Usage::
208 Usage::
204
209
205 templatefilter = registrar.templatefilter()
210 templatefilter = registrar.templatefilter()
206
211
207 @templatefilter('myfilter')
212 @templatefilter('myfilter')
208 def myfilterfunc(text):
213 def myfilterfunc(text):
209 '''Explanation of this template filter ....
214 '''Explanation of this template filter ....
210 '''
215 '''
211 pass
216 pass
212
217
213 The first string argument is used also in online help.
218 The first string argument is used also in online help.
214
219
215 'templatefilter' instance in example above can be used to
220 'templatefilter' instance in example above can be used to
216 decorate multiple functions.
221 decorate multiple functions.
217
222
218 Decorated functions are registered automatically at loading
223 Decorated functions are registered automatically at loading
219 extension, if an instance named as 'templatefilter' is used for
224 extension, if an instance named as 'templatefilter' is used for
220 decorating in extension.
225 decorating in extension.
221
226
222 Otherwise, explicit 'templatefilters.loadkeyword()' is needed.
227 Otherwise, explicit 'templatefilters.loadkeyword()' is needed.
223 """
228 """
224
229
225 class templatefunc(_templateregistrarbase):
230 class templatefunc(_templateregistrarbase):
226 """Decorator to register template function
231 """Decorator to register template function
227
232
228 Usage::
233 Usage::
229
234
230 templatefunc = registrar.templatefunc()
235 templatefunc = registrar.templatefunc()
231
236
232 @templatefunc('myfunc(arg1, arg2[, arg3])')
237 @templatefunc('myfunc(arg1, arg2[, arg3])')
233 def myfuncfunc(context, mapping, args):
238 def myfuncfunc(context, mapping, args):
234 '''Explanation of this template function ....
239 '''Explanation of this template function ....
235 '''
240 '''
236 pass
241 pass
237
242
238 The first string argument is used also in online help.
243 The first string argument is used also in online help.
239
244
240 'templatefunc' instance in example above can be used to
245 'templatefunc' instance in example above can be used to
241 decorate multiple functions.
246 decorate multiple functions.
242
247
243 Decorated functions are registered automatically at loading
248 Decorated functions are registered automatically at loading
244 extension, if an instance named as 'templatefunc' is used for
249 extension, if an instance named as 'templatefunc' is used for
245 decorating in extension.
250 decorating in extension.
246
251
247 Otherwise, explicit 'templater.loadfunction()' is needed.
252 Otherwise, explicit 'templater.loadfunction()' is needed.
248 """
253 """
249 _getname = _funcregistrarbase._parsefuncdecl
254 _getname = _funcregistrarbase._parsefuncdecl
General Comments 0
You need to be logged in to leave comments. Login now