##// END OF EJS Templates
templater: abstract min/max away...
Yuya Nishihara -
r38284:41ae9b3c default
parent child Browse files
Show More
@@ -717,6 +717,12 b' class sessionvars(templateutil.wrapped):'
717 717 key = templateutil.unwrapvalue(context, mapping, key)
718 718 return self._vars.get(key)
719 719
720 def getmin(self, context, mapping):
721 raise error.ParseError(_('not comparable'))
722
723 def getmax(self, context, mapping):
724 raise error.ParseError(_('not comparable'))
725
720 726 def itermaps(self, context):
721 727 separator = self._start
722 728 for key, value in sorted(self._vars.iteritems()):
@@ -20,7 +20,6 b' from . import ('
20 20 error,
21 21 minirst,
22 22 obsutil,
23 pycompat,
24 23 registrar,
25 24 revset as revsetmod,
26 25 revsetlang,
@@ -404,13 +403,13 b' def max_(context, mapping, args, **kwarg'
404 403 # i18n: "max" is a keyword
405 404 raise error.ParseError(_("max expects one argument"))
406 405
407 iterable = evalfuncarg(context, mapping, args[0])
406 iterable = evalwrapped(context, mapping, args[0])
408 407 try:
409 x = max(pycompat.maybebytestr(iterable))
410 except (TypeError, ValueError):
408 return iterable.getmax(context, mapping)
409 except error.ParseError as err:
411 410 # i18n: "max" is a keyword
412 raise error.ParseError(_("max first argument should be an iterable"))
413 return templateutil.wraphybridvalue(iterable, x, x)
411 hint = _("max first argument should be an iterable")
412 raise error.ParseError(bytes(err), hint=hint)
414 413
415 414 @templatefunc('min(iterable)')
416 415 def min_(context, mapping, args, **kwargs):
@@ -419,13 +418,13 b' def min_(context, mapping, args, **kwarg'
419 418 # i18n: "min" is a keyword
420 419 raise error.ParseError(_("min expects one argument"))
421 420
422 iterable = evalfuncarg(context, mapping, args[0])
421 iterable = evalwrapped(context, mapping, args[0])
423 422 try:
424 x = min(pycompat.maybebytestr(iterable))
425 except (TypeError, ValueError):
423 return iterable.getmin(context, mapping)
424 except error.ParseError as err:
426 425 # i18n: "min" is a keyword
427 raise error.ParseError(_("min first argument should be an iterable"))
428 return templateutil.wraphybridvalue(iterable, x, x)
426 hint = _("min first argument should be an iterable")
427 raise error.ParseError(bytes(err), hint=hint)
429 428
430 429 @templatefunc('mod(a, b)')
431 430 def mod(context, mapping, args):
@@ -47,6 +47,16 b' class wrapped(object):'
47 47 """
48 48
49 49 @abc.abstractmethod
50 def getmin(self, context, mapping):
51 """Return the smallest item, which may be either a wrapped or a pure
52 value depending on the self type"""
53
54 @abc.abstractmethod
55 def getmax(self, context, mapping):
56 """Return the largest item, which may be either a wrapped or a pure
57 value depending on the self type"""
58
59 @abc.abstractmethod
50 60 def itermaps(self, context):
51 61 """Yield each template mapping"""
52 62
@@ -85,6 +95,17 b' class wrappedbytes(wrapped):'
85 95 raise error.ParseError(_('%r is not a dictionary')
86 96 % pycompat.bytestr(self._value))
87 97
98 def getmin(self, context, mapping):
99 return self._getby(context, mapping, min)
100
101 def getmax(self, context, mapping):
102 return self._getby(context, mapping, max)
103
104 def _getby(self, context, mapping, func):
105 if not self._value:
106 raise error.ParseError(_('empty string'))
107 return func(pycompat.iterbytestr(self._value))
108
88 109 def itermaps(self, context):
89 110 raise error.ParseError(_('%r is not iterable of mappings')
90 111 % pycompat.bytestr(self._value))
@@ -107,6 +128,12 b' class wrappedvalue(wrapped):'
107 128 def getmember(self, context, mapping, key):
108 129 raise error.ParseError(_('%r is not a dictionary') % self._value)
109 130
131 def getmin(self, context, mapping):
132 raise error.ParseError(_("%r is not iterable") % self._value)
133
134 def getmax(self, context, mapping):
135 raise error.ParseError(_("%r is not iterable") % self._value)
136
110 137 def itermaps(self, context):
111 138 raise error.ParseError(_('%r is not iterable of mappings')
112 139 % self._value)
@@ -151,6 +178,18 b' class hybrid(wrapped):'
151 178 key = unwrapastype(context, mapping, key, self.keytype)
152 179 return self._wrapvalue(key, self._values.get(key))
153 180
181 def getmin(self, context, mapping):
182 return self._getby(context, mapping, min)
183
184 def getmax(self, context, mapping):
185 return self._getby(context, mapping, max)
186
187 def _getby(self, context, mapping, func):
188 if not self._values:
189 raise error.ParseError(_('empty sequence'))
190 val = func(self._values)
191 return self._wrapvalue(val, val)
192
154 193 def _wrapvalue(self, key, val):
155 194 if val is None:
156 195 return
@@ -217,6 +256,14 b' class mappable(wrapped):'
217 256 w = makewrapped(context, mapping, self._value)
218 257 return w.getmember(context, mapping, key)
219 258
259 def getmin(self, context, mapping):
260 w = makewrapped(context, mapping, self._value)
261 return w.getmin(context, mapping)
262
263 def getmax(self, context, mapping):
264 w = makewrapped(context, mapping, self._value)
265 return w.getmax(context, mapping)
266
220 267 def itermaps(self, context):
221 268 yield self.tomap()
222 269
@@ -255,6 +302,12 b' class _mappingsequence(wrapped):'
255 302 def getmember(self, context, mapping, key):
256 303 raise error.ParseError(_('not a dictionary'))
257 304
305 def getmin(self, context, mapping):
306 raise error.ParseError(_('not comparable'))
307
308 def getmax(self, context, mapping):
309 raise error.ParseError(_('not comparable'))
310
258 311 def join(self, context, mapping, sep):
259 312 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
260 313 if self._name:
@@ -321,6 +374,18 b' class mappedgenerator(wrapped):'
321 374 def getmember(self, context, mapping, key):
322 375 raise error.ParseError(_('not a dictionary'))
323 376
377 def getmin(self, context, mapping):
378 return self._getby(context, mapping, min)
379
380 def getmax(self, context, mapping):
381 return self._getby(context, mapping, max)
382
383 def _getby(self, context, mapping, func):
384 xs = self.tovalue(context, mapping)
385 if not xs:
386 raise error.ParseError(_('empty sequence'))
387 return func(xs)
388
324 389 def itermaps(self, context):
325 390 raise error.ParseError(_('list of strings is not mappable'))
326 391
@@ -3274,6 +3274,51 b' Test min/max over map operation:'
3274 3274 $ hg log -R latesttag -r3 -T '{max(tags % "{tag}")}\n'
3275 3275 t3
3276 3276
3277 Test min/max of strings:
3278
3279 $ hg log -R latesttag -l1 -T '{min(desc)}\n'
3280 3
3281 $ hg log -R latesttag -l1 -T '{max(desc)}\n'
3282 t
3283
3284 Test min/max of non-iterable:
3285
3286 $ hg debugtemplate '{min(1)}'
3287 hg: parse error: 1 is not iterable
3288 (min first argument should be an iterable)
3289 [255]
3290 $ hg debugtemplate '{max(2)}'
3291 hg: parse error: 2 is not iterable
3292 (max first argument should be an iterable)
3293 [255]
3294
3295 Test min/max of empty sequence:
3296
3297 $ hg debugtemplate '{min("")}'
3298 hg: parse error: empty string
3299 (min first argument should be an iterable)
3300 [255]
3301 $ hg debugtemplate '{max("")}'
3302 hg: parse error: empty string
3303 (max first argument should be an iterable)
3304 [255]
3305 $ hg debugtemplate '{min(dict())}'
3306 hg: parse error: empty sequence
3307 (min first argument should be an iterable)
3308 [255]
3309 $ hg debugtemplate '{max(dict())}'
3310 hg: parse error: empty sequence
3311 (max first argument should be an iterable)
3312 [255]
3313 $ hg debugtemplate '{min(dict() % "")}'
3314 hg: parse error: empty sequence
3315 (min first argument should be an iterable)
3316 [255]
3317 $ hg debugtemplate '{max(dict() % "")}'
3318 hg: parse error: empty sequence
3319 (max first argument should be an iterable)
3320 [255]
3321
3277 3322 Test min/max of if() result
3278 3323
3279 3324 $ cd latesttag
General Comments 0
You need to be logged in to leave comments. Login now