Mercurial > hg
comparison mercurial/registrar.py @ 27583:37d50250b696
registrar: add funcregistrar class to register function for specific purpose
This class centralizes the common logic to register function for
specific purpose like below:
- template keyword, filter and function
- revset predicate
- fileset predicate
- webcommand
'funcregistrar' also formats help document of the function with the
'decl'(aration) specified at the construction.
This can avoid (1) redundancy between 'decl' and help document, and
(2) accidental typo of help document. For example, 'foo' should appear
twice like below, if without such formatting:
@keyword('foo')
def foo(....):
""":foo: Explanation of keyword foo ..."""
Almost all cases needs very simple document formatting like below:
- "``DECL``\n EXPLANATION"
- ":DECL: EXPLANATION"
But webcommand needs a little complicated formatting like:
/PATH/SPEC
----------
EXPLANATION ....
To make minirst recognize the section header, hyphen line should be as
long as "/PATH/SPEC". It should be arranged by program.
Implementing 'formatdoc()' in derived class can support complicated
formatting in the latter case. But it seems redundant for simple one
in the former case.
Therefore, 'funcregistrar' does:
- invoke 'self.formatdoc', if it is callable (for the latter case)
- use it as the format string, otherwise (for the former case)
author | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> |
---|---|
date | Tue, 29 Dec 2015 23:58:30 +0900 |
parents | |
children | fc7c8cac6a4b |
comparison
equal
deleted
inserted
replaced
27582:8f8f3b13252d | 27583:37d50250b696 |
---|---|
1 # registrar.py - utilities to register function for specific purpose | |
2 # | |
3 # Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others | |
4 # | |
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. | |
7 | |
8 from __future__ import absolute_import | |
9 | |
10 from . import ( | |
11 util, | |
12 ) | |
13 | |
14 class funcregistrar(object): | |
15 """Base of decorator to register a fuction for specific purpose | |
16 | |
17 The least derived class can be defined by overriding 'table' and | |
18 'formatdoc', for example:: | |
19 | |
20 symbols = {} | |
21 class keyword(funcregistrar): | |
22 table = symbols | |
23 formatdoc = ":%s: %s" | |
24 | |
25 @keyword('bar') | |
26 def barfunc(*args, **kwargs): | |
27 '''Explanation of bar keyword .... | |
28 ''' | |
29 pass | |
30 | |
31 In this case: | |
32 | |
33 - 'barfunc' is registered as 'bar' in 'symbols' | |
34 - online help uses ":bar: Explanation of bar keyword" | |
35 """ | |
36 | |
37 def __init__(self, decl): | |
38 """'decl' is a name or more descriptive string of a function | |
39 | |
40 Specification of 'decl' depends on registration purpose. | |
41 """ | |
42 self.decl = decl | |
43 | |
44 table = None | |
45 | |
46 def __call__(self, func): | |
47 """Execute actual registration for specified function | |
48 """ | |
49 name = self.getname() | |
50 | |
51 if func.__doc__ and not util.safehasattr(func, '_origdoc'): | |
52 doc = func.__doc__.strip() | |
53 func._origdoc = doc | |
54 if callable(self.formatdoc): | |
55 func.__doc__ = self.formatdoc(doc) | |
56 else: | |
57 # convenient shortcut for simple format | |
58 func.__doc__ = self.formatdoc % (self.decl, doc) | |
59 | |
60 self.table[name] = func | |
61 self.extraaction(name, func) | |
62 | |
63 return func | |
64 | |
65 def getname(self): | |
66 """Return the name of the registered function from self.decl | |
67 | |
68 Derived class should override this, if it allows more | |
69 descriptive 'decl' string than just a name. | |
70 """ | |
71 return self.decl | |
72 | |
73 def formatdoc(self, doc): | |
74 """Return formatted document of the registered function for help | |
75 | |
76 'doc' is '__doc__.strip()' of the registered function. | |
77 | |
78 If this is overridden by non-callable object in derived class, | |
79 such value is treated as "format string" and used to format | |
80 document by 'self.formatdoc % (self.decl, doc)' for convenience. | |
81 """ | |
82 raise NotImplementedError() | |
83 | |
84 def extraaction(self, name, func): | |
85 """Execute exra action for registered function, if needed | |
86 """ | |
87 pass |