Patchwork [2,of,8] templater: define interface for objects requiring unwraphybrid()

login
register
mail settings
Submitter Yuya Nishihara
Date April 1, 2018, 2:45 a.m.
Message ID <a26aace92f3a4e7e0acf.1522550759@mimosa>
Download mbox | patch
Permalink /patch/30089/
State Deferred
Headers show

Comments

Yuya Nishihara - April 1, 2018, 2:45 a.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1521287570 -32400
#      Sat Mar 17 20:52:50 2018 +0900
# Node ID a26aace92f3a4e7e0acfa8d0e61ad11ec182902c
# Parent  529838f7858556c0f9d180a276b483578c6d55d4
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):
      return (context.expand(self._tmpl, m) for m in self._mappings)

Patch

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,22 @@  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):
+        """Return a bytes or (possibly nested) generator of bytes"""
+
 # 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 +71,14 @@  class hybrid(object):
         makemap = self._makemap
         for x in self._values:
             yield makemap(x)
+
+    def show(self, context):
+        # TODO: switch gen to context-based 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 +93,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 +122,13 @@  class mappable(object):
     def itermaps(self):
         yield self.tomap()
 
+    def show(self, context):
+        # TODO: switch gen to context-based 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 +149,9 @@  def hybridlist(data, name, fmt=None, gen
 def unwraphybrid(context, 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)
 
 def unwrapvalue(thing):
     """Move the inner value object out of the wrapper"""