mercurial/templateutil.py
changeset 38265 41ae9b3cbfb9
parent 38244 688fbb758ba9
child 38266 80f423a14c90
--- a/mercurial/templateutil.py	Sun Jun 10 12:24:53 2018 +0900
+++ b/mercurial/templateutil.py	Mon Mar 19 00:16:12 2018 +0900
@@ -47,6 +47,16 @@
         """
 
     @abc.abstractmethod
+    def getmin(self, context, mapping):
+        """Return the smallest item, which may be either a wrapped or a pure
+        value depending on the self type"""
+
+    @abc.abstractmethod
+    def getmax(self, context, mapping):
+        """Return the largest item, which may be either a wrapped or a pure
+        value depending on the self type"""
+
+    @abc.abstractmethod
     def itermaps(self, context):
         """Yield each template mapping"""
 
@@ -85,6 +95,17 @@
         raise error.ParseError(_('%r is not a dictionary')
                                % pycompat.bytestr(self._value))
 
+    def getmin(self, context, mapping):
+        return self._getby(context, mapping, min)
+
+    def getmax(self, context, mapping):
+        return self._getby(context, mapping, max)
+
+    def _getby(self, context, mapping, func):
+        if not self._value:
+            raise error.ParseError(_('empty string'))
+        return func(pycompat.iterbytestr(self._value))
+
     def itermaps(self, context):
         raise error.ParseError(_('%r is not iterable of mappings')
                                % pycompat.bytestr(self._value))
@@ -107,6 +128,12 @@
     def getmember(self, context, mapping, key):
         raise error.ParseError(_('%r is not a dictionary') % self._value)
 
+    def getmin(self, context, mapping):
+        raise error.ParseError(_("%r is not iterable") % self._value)
+
+    def getmax(self, context, mapping):
+        raise error.ParseError(_("%r is not iterable") % self._value)
+
     def itermaps(self, context):
         raise error.ParseError(_('%r is not iterable of mappings')
                                % self._value)
@@ -151,6 +178,18 @@
         key = unwrapastype(context, mapping, key, self.keytype)
         return self._wrapvalue(key, self._values.get(key))
 
+    def getmin(self, context, mapping):
+        return self._getby(context, mapping, min)
+
+    def getmax(self, context, mapping):
+        return self._getby(context, mapping, max)
+
+    def _getby(self, context, mapping, func):
+        if not self._values:
+            raise error.ParseError(_('empty sequence'))
+        val = func(self._values)
+        return self._wrapvalue(val, val)
+
     def _wrapvalue(self, key, val):
         if val is None:
             return
@@ -217,6 +256,14 @@
         w = makewrapped(context, mapping, self._value)
         return w.getmember(context, mapping, key)
 
+    def getmin(self, context, mapping):
+        w = makewrapped(context, mapping, self._value)
+        return w.getmin(context, mapping)
+
+    def getmax(self, context, mapping):
+        w = makewrapped(context, mapping, self._value)
+        return w.getmax(context, mapping)
+
     def itermaps(self, context):
         yield self.tomap()
 
@@ -255,6 +302,12 @@
     def getmember(self, context, mapping, key):
         raise error.ParseError(_('not a dictionary'))
 
+    def getmin(self, context, mapping):
+        raise error.ParseError(_('not comparable'))
+
+    def getmax(self, context, mapping):
+        raise error.ParseError(_('not comparable'))
+
     def join(self, context, mapping, sep):
         mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
         if self._name:
@@ -321,6 +374,18 @@
     def getmember(self, context, mapping, key):
         raise error.ParseError(_('not a dictionary'))
 
+    def getmin(self, context, mapping):
+        return self._getby(context, mapping, min)
+
+    def getmax(self, context, mapping):
+        return self._getby(context, mapping, max)
+
+    def _getby(self, context, mapping, func):
+        xs = self.tovalue(context, mapping)
+        if not xs:
+            raise error.ParseError(_('empty sequence'))
+        return func(xs)
+
     def itermaps(self, context):
         raise error.ParseError(_('list of strings is not mappable'))