Mercurial > hg
comparison mercurial/templateutil.py @ 37273:83e1bbd48991
templater: define interface for objects requiring unwraphybrid()
Prepares for introducing another hybrid-like data type. show() takes context
as an argument so a wrapper class may render its items by pre-configured
template:
def show(self, context, mapping):
return (context.expand(self._tmpl, mapping + lm) for lm in self._mappings)
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 17 Mar 2018 20:52:50 +0900 |
parents | 7d3bc1d4e871 |
children | 8c84dc8264dc |
comparison
equal
deleted
inserted
replaced
37272:7d3bc1d4e871 | 37273:83e1bbd48991 |
---|---|
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 import abc | |
10 import types | 11 import types |
11 | 12 |
12 from .i18n import _ | 13 from .i18n import _ |
13 from . import ( | 14 from . import ( |
14 error, | 15 error, |
24 pass | 25 pass |
25 | 26 |
26 class TemplateNotFound(error.Abort): | 27 class TemplateNotFound(error.Abort): |
27 pass | 28 pass |
28 | 29 |
30 class wrapped(object): | |
31 """Object requiring extra conversion prior to displaying or processing | |
32 as value""" | |
33 | |
34 __metaclass__ = abc.ABCMeta | |
35 | |
36 @abc.abstractmethod | |
37 def show(self, context, mapping): | |
38 """Return a bytes or (possibly nested) generator of bytes representing | |
39 the underlying object | |
40 | |
41 A pre-configured template may be rendered if the underlying object is | |
42 not printable. | |
43 """ | |
44 | |
29 # stub for representing a date type; may be a real date type that can | 45 # stub for representing a date type; may be a real date type that can |
30 # provide a readable string value | 46 # provide a readable string value |
31 class date(object): | 47 class date(object): |
32 pass | 48 pass |
33 | 49 |
34 class hybrid(object): | 50 class hybrid(wrapped): |
35 """Wrapper for list or dict to support legacy template | 51 """Wrapper for list or dict to support legacy template |
36 | 52 |
37 This class allows us to handle both: | 53 This class allows us to handle both: |
38 - "{files}" (legacy command-line-specific list hack) and | 54 - "{files}" (legacy command-line-specific list hack) and |
39 - "{files % '{file}\n'}" (hgweb-style with inlining and function support) | 55 - "{files % '{file}\n'}" (hgweb-style with inlining and function support) |
58 yield self.joinfmt(x) | 74 yield self.joinfmt(x) |
59 def itermaps(self): | 75 def itermaps(self): |
60 makemap = self._makemap | 76 makemap = self._makemap |
61 for x in self._values: | 77 for x in self._values: |
62 yield makemap(x) | 78 yield makemap(x) |
79 | |
80 def show(self, context, mapping): | |
81 # TODO: switch gen to (context, mapping) API? | |
82 gen = self.gen | |
83 if callable(gen): | |
84 return gen() | |
85 return gen | |
86 | |
63 def __contains__(self, x): | 87 def __contains__(self, x): |
64 return x in self._values | 88 return x in self._values |
65 def __getitem__(self, key): | 89 def __getitem__(self, key): |
66 return self._values[key] | 90 return self._values[key] |
67 def __len__(self): | 91 def __len__(self): |
72 if name not in (r'get', r'items', r'iteritems', r'iterkeys', | 96 if name not in (r'get', r'items', r'iteritems', r'iterkeys', |
73 r'itervalues', r'keys', r'values'): | 97 r'itervalues', r'keys', r'values'): |
74 raise AttributeError(name) | 98 raise AttributeError(name) |
75 return getattr(self._values, name) | 99 return getattr(self._values, name) |
76 | 100 |
77 class mappable(object): | 101 class mappable(wrapped): |
78 """Wrapper for non-list/dict object to support map operation | 102 """Wrapper for non-list/dict object to support map operation |
79 | 103 |
80 This class allows us to handle both: | 104 This class allows us to handle both: |
81 - "{manifest}" | 105 - "{manifest}" |
82 - "{manifest % '{rev}:{node}'}" | 106 - "{manifest % '{rev}:{node}'}" |
100 def tomap(self): | 124 def tomap(self): |
101 return self._makemap(self._key) | 125 return self._makemap(self._key) |
102 | 126 |
103 def itermaps(self): | 127 def itermaps(self): |
104 yield self.tomap() | 128 yield self.tomap() |
129 | |
130 def show(self, context, mapping): | |
131 # TODO: switch gen to (context, mapping) API? | |
132 gen = self.gen | |
133 if callable(gen): | |
134 return gen() | |
135 return gen | |
105 | 136 |
106 def hybriddict(data, key='key', value='value', fmt=None, gen=None): | 137 def hybriddict(data, key='key', value='value', fmt=None, gen=None): |
107 """Wrap data to support both dict-like and string-like operations""" | 138 """Wrap data to support both dict-like and string-like operations""" |
108 prefmt = pycompat.identity | 139 prefmt = pycompat.identity |
109 if fmt is None: | 140 if fmt is None: |
121 return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x)) | 152 return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x)) |
122 | 153 |
123 def unwraphybrid(context, mapping, thing): | 154 def unwraphybrid(context, mapping, thing): |
124 """Return an object which can be stringified possibly by using a legacy | 155 """Return an object which can be stringified possibly by using a legacy |
125 template""" | 156 template""" |
126 gen = getattr(thing, 'gen', None) | 157 if not isinstance(thing, wrapped): |
127 if gen is None: | |
128 return thing | 158 return thing |
129 if callable(gen): | 159 return thing.show(context, mapping) |
130 return gen() | |
131 return gen | |
132 | 160 |
133 def unwrapvalue(thing): | 161 def unwrapvalue(thing): |
134 """Move the inner value object out of the wrapper""" | 162 """Move the inner value object out of the wrapper""" |
135 if not util.safehasattr(thing, '_value'): | 163 if not util.safehasattr(thing, '_value'): |
136 return thing | 164 return thing |