[PATCH 2 of 8 V2] templater: define interface for objects requiring unwraphybrid()

Yuya Nishihara yuya at tcha.org
Tue Apr 3 11:40:04 EDT 2018


# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1521287570 -32400
#      Sat Mar 17 20:52:50 2018 +0900
# Node ID b02b53e4cc2049324d69e3c4a16357f79400a5e4
# Parent  164e39f1fc56cebdaa441458dfa6436939c97267
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)

diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py
--- a/mercurial/templateutil.py
+++ b/mercurial/templateutil.py
@@ -7,6 +7,7 @@
 
 from __future__ import absolute_import
 
+import abc
 import types
 
 from .i18n import _
@@ -26,12 +27,27 @@ class ResourceUnavailable(error.Abort):
 class TemplateNotFound(error.Abort):
     pass
 
+class wrapped(object):
+    """Object requiring extra conversion prior to displaying or processing
+    as value"""
+
+    __metaclass__ = abc.ABCMeta
+
+    @abc.abstractmethod
+    def show(self, context, mapping):
+        """Return a bytes or (possibly nested) generator of bytes representing
+        the underlying object
+
+        A pre-configured template may be rendered if the underlying object is
+        not printable.
+        """
+
 # stub for representing a date type; may be a real date type that can
 # provide a readable string value
 class date(object):
     pass
 
-class hybrid(object):
+class hybrid(wrapped):
     """Wrapper for list or dict to support legacy template
 
     This class allows us to handle both:
@@ -60,6 +76,14 @@ class hybrid(object):
         makemap = self._makemap
         for x in self._values:
             yield makemap(x)
+
+    def show(self, context, mapping):
+        # TODO: switch gen to (context, mapping) API?
+        gen = self.gen
+        if callable(gen):
+            return gen()
+        return gen
+
     def __contains__(self, x):
         return x in self._values
     def __getitem__(self, key):
@@ -74,7 +98,7 @@ class hybrid(object):
             raise AttributeError(name)
         return getattr(self._values, name)
 
-class mappable(object):
+class mappable(wrapped):
     """Wrapper for non-list/dict object to support map operation
 
     This class allows us to handle both:
@@ -103,6 +127,13 @@ class mappable(object):
     def itermaps(self):
         yield self.tomap()
 
+    def show(self, context, mapping):
+        # TODO: switch gen to (context, mapping) API?
+        gen = self.gen
+        if callable(gen):
+            return gen()
+        return gen
+
 def hybriddict(data, key='key', value='value', fmt=None, gen=None):
     """Wrap data to support both dict-like and string-like operations"""
     prefmt = pycompat.identity
@@ -123,12 +154,9 @@ def hybridlist(data, name, fmt=None, gen
 def unwraphybrid(context, mapping, thing):
     """Return an object which can be stringified possibly by using a legacy
     template"""
-    gen = getattr(thing, 'gen', None)
-    if gen is None:
+    if not isinstance(thing, wrapped):
         return thing
-    if callable(gen):
-        return gen()
-    return gen
+    return thing.show(context, mapping)
 
 def unwrapvalue(thing):
     """Move the inner value object out of the wrapper"""


More information about the Mercurial-devel mailing list