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