comparison mercurial/templateutil.py @ 38255:06d11cd90516

templater: promote getmember() to an interface of wrapped types
author Yuya Nishihara <yuya@tcha.org>
date Wed, 21 Mar 2018 11:30:21 +0900
parents 12b6ee9e88f3
children 688fbb758ba9
comparison
equal deleted inserted replaced
38254:12b6ee9e88f3 38255:06d11cd90516
36 """ 36 """
37 37
38 __metaclass__ = abc.ABCMeta 38 __metaclass__ = abc.ABCMeta
39 39
40 @abc.abstractmethod 40 @abc.abstractmethod
41 def getmember(self, context, mapping, key):
42 """Return a member item for the specified key
43
44 A returned object may be either a wrapped object or a pure value
45 depending on the self type.
46 """
47
48 @abc.abstractmethod
41 def itermaps(self, context): 49 def itermaps(self, context):
42 """Yield each template mapping""" 50 """Yield each template mapping"""
43 51
44 @abc.abstractmethod 52 @abc.abstractmethod
45 def join(self, context, mapping, sep): 53 def join(self, context, mapping, sep):
70 """Wrapper for byte string""" 78 """Wrapper for byte string"""
71 79
72 def __init__(self, value): 80 def __init__(self, value):
73 self._value = value 81 self._value = value
74 82
83 def getmember(self, context, mapping, key):
84 raise error.ParseError(_('%r is not a dictionary')
85 % pycompat.bytestr(self._value))
86
75 def itermaps(self, context): 87 def itermaps(self, context):
76 raise error.ParseError(_('%r is not iterable of mappings') 88 raise error.ParseError(_('%r is not iterable of mappings')
77 % pycompat.bytestr(self._value)) 89 % pycompat.bytestr(self._value))
78 90
79 def join(self, context, mapping, sep): 91 def join(self, context, mapping, sep):
88 class wrappedvalue(wrapped): 100 class wrappedvalue(wrapped):
89 """Generic wrapper for pure non-list/dict/bytes value""" 101 """Generic wrapper for pure non-list/dict/bytes value"""
90 102
91 def __init__(self, value): 103 def __init__(self, value):
92 self._value = value 104 self._value = value
105
106 def getmember(self, context, mapping, key):
107 raise error.ParseError(_('%r is not a dictionary') % self._value)
93 108
94 def itermaps(self, context): 109 def itermaps(self, context):
95 raise error.ParseError(_('%r is not iterable of mappings') 110 raise error.ParseError(_('%r is not iterable of mappings')
96 % self._value) 111 % self._value)
97 112
194 self._makemap = makemap 209 self._makemap = makemap
195 210
196 def tomap(self): 211 def tomap(self):
197 return self._makemap(self._key) 212 return self._makemap(self._key)
198 213
214 def getmember(self, context, mapping, key):
215 w = makewrapped(context, mapping, self._value)
216 return w.getmember(context, mapping, key)
217
199 def itermaps(self, context): 218 def itermaps(self, context):
200 yield self.tomap() 219 yield self.tomap()
201 220
202 def join(self, context, mapping, sep): 221 def join(self, context, mapping, sep):
203 w = makewrapped(context, mapping, self._value) 222 w = makewrapped(context, mapping, self._value)
228 if name is not None and tmpl is not None: 247 if name is not None and tmpl is not None:
229 raise error.ProgrammingError('name and tmpl are mutually exclusive') 248 raise error.ProgrammingError('name and tmpl are mutually exclusive')
230 self._name = name 249 self._name = name
231 self._tmpl = tmpl 250 self._tmpl = tmpl
232 self._defaultsep = sep 251 self._defaultsep = sep
252
253 def getmember(self, context, mapping, key):
254 raise error.ParseError(_('not a dictionary'))
233 255
234 def join(self, context, mapping, sep): 256 def join(self, context, mapping, sep):
235 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context)) 257 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
236 if self._name: 258 if self._name:
237 itemiter = (context.process(self._name, m) for m in mapsiter) 259 itemiter = (context.process(self._name, m) for m in mapsiter)
291 self._make = make 313 self._make = make
292 self._args = args 314 self._args = args
293 315
294 def _gen(self, context): 316 def _gen(self, context):
295 return self._make(context, *self._args) 317 return self._make(context, *self._args)
318
319 def getmember(self, context, mapping, key):
320 raise error.ParseError(_('not a dictionary'))
296 321
297 def itermaps(self, context): 322 def itermaps(self, context):
298 raise error.ParseError(_('list of strings is not mappable')) 323 raise error.ParseError(_('list of strings is not mappable'))
299 324
300 def join(self, context, mapping, sep): 325 def join(self, context, mapping, sep):
676 d = evalwrapped(context, mapping, darg) 701 d = evalwrapped(context, mapping, darg)
677 if util.safehasattr(d, 'tomap'): 702 if util.safehasattr(d, 'tomap'):
678 lm = context.overlaymap(mapping, d.tomap()) 703 lm = context.overlaymap(mapping, d.tomap())
679 return runsymbol(context, lm, memb) 704 return runsymbol(context, lm, memb)
680 try: 705 try:
681 if util.safehasattr(d, 'getmember'): 706 return d.getmember(context, mapping, memb)
682 return d.getmember(context, mapping, memb) 707 except error.ParseError as err:
683 raise error.ParseError
684 except error.ParseError:
685 sym = findsymbolicname(darg) 708 sym = findsymbolicname(darg)
686 if sym: 709 if not sym:
687 raise error.ParseError(_("keyword '%s' has no member") % sym) 710 raise
688 else: 711 hint = _("keyword '%s' does not support member operation") % sym
689 raise error.ParseError(_("%r has no member") % pycompat.bytestr(d)) 712 raise error.ParseError(bytes(err), hint=hint)
690 713
691 def runnegate(context, mapping, data): 714 def runnegate(context, mapping, data):
692 data = evalinteger(context, mapping, data, 715 data = evalinteger(context, mapping, data,
693 _('negation needs an integer argument')) 716 _('negation needs an integer argument'))
694 return -data 717 return -data