Patchwork [2,of,7] templater: promote tomap() to an interface type

login
register
mail settings
Submitter Yuya Nishihara
Date June 12, 2018, 2:49 p.m.
Message ID <5eb83a63ffff10845fb6.1528814944@mimosa>
Download mbox | patch
Permalink /patch/32078/
State Accepted
Headers show

Comments

Yuya Nishihara - June 12, 2018, 2:49 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1524304895 -32400
#      Sat Apr 21 19:01:35 2018 +0900
# Node ID 5eb83a63ffff10845fb61fef9eda799731b90061
# Parent  9c54939508aa66b09f2384ac37974addbabb90e9
templater: promote tomap() to an interface type

I originally considered merging tomap() with itermaps()/getmember(), but
decided to not. We might want to add support for chained map operations
(e.g. {foo % func() % ...}), where func() will return a mappable object,
and 'foo % func()' will be a mappedgenerator of mappable objects.

Patch

diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py
--- a/mercurial/templateutil.py
+++ b/mercurial/templateutil.py
@@ -91,6 +91,16 @@  class wrapped(object):
         A returned value must be serializable by templaterfilters.json().
         """
 
+class mappable(object):
+    """Object which can be converted to a single template mapping"""
+
+    def itermaps(self, context):
+        yield self.tomap(context)
+
+    @abc.abstractmethod
+    def tomap(self, context):
+        """Create a single template mapping representing this"""
+
 class wrappedbytes(wrapped):
     """Wrapper for byte string"""
 
@@ -243,7 +253,7 @@  class hybrid(wrapped):
                     for k, v in xs.iteritems()}
         return [unwrapvalue(context, mapping, x) for x in xs]
 
-class hybriditem(wrapped):
+class hybriditem(mappable, wrapped):
     """Wrapper for non-list/dict object to support map operation
 
     This class allows us to handle both:
@@ -258,7 +268,7 @@  class hybriditem(wrapped):
         self._value = value  # may be generator of strings
         self._makemap = makemap
 
-    def tomap(self):
+    def tomap(self, context):
         return self._makemap(self._key)
 
     def contains(self, context, mapping, item):
@@ -277,9 +287,6 @@  class hybriditem(wrapped):
         w = makewrapped(context, mapping, self._value)
         return w.getmax(context, mapping)
 
-    def itermaps(self, context):
-        yield self.tomap()
-
     def join(self, context, mapping, sep):
         w = makewrapped(context, mapping, self._value)
         return w.join(context, mapping, sep)
@@ -775,8 +782,8 @@  def runmap(context, mapping, data):
 def runmember(context, mapping, data):
     darg, memb = data
     d = evalwrapped(context, mapping, darg)
-    if util.safehasattr(d, 'tomap'):
-        lm = context.overlaymap(mapping, d.tomap())
+    if isinstance(d, mappable):
+        lm = context.overlaymap(mapping, d.tomap(context))
         return runsymbol(context, lm, memb)
     try:
         return d.getmember(context, mapping, memb)