Patchwork [3,of,6] templater: add wrapped types for pure non-list/dict values

login
register
mail settings
Submitter Yuya Nishihara
Date June 4, 2018, 1:10 p.m.
Message ID <530b24e26effdc6f4611.1528117810@mimosa>
Download mbox | patch
Permalink /patch/31962/
State Accepted
Headers show

Comments

Yuya Nishihara - June 4, 2018, 1:10 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1521557786 -32400
#      Tue Mar 20 23:56:26 2018 +0900
# Node ID 530b24e26effdc6f4611e444d8f41c6bf88e706b
# Parent  39d5832512a0495480068c761a9e081230aac737
templater: add wrapped types for pure non-list/dict values

These wrapper types will allow us to get rid of some isinstance() business.

A bytes object needs to support sequence-like operations (e.g. join(),
ifcontains(), etc.) That's why we have two wrapper classes.

Tests will be added later.

Patch

diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -32,6 +32,9 @@  None
 True, False, int, float
     can be stringified as such.
 
+wrappedbytes, wrappedvalue
+    a wrapper for the above printable types.
+
 date tuple
     a (unixtime, offset) tuple, which produces no meaningful output by itself.
 
diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py
--- a/mercurial/templateutil.py
+++ b/mercurial/templateutil.py
@@ -66,6 +66,44 @@  class wrapped(object):
         A returned value must be serializable by templaterfilters.json().
         """
 
+class wrappedbytes(wrapped):
+    """Wrapper for byte string"""
+
+    def __init__(self, value):
+        self._value = value
+
+    def itermaps(self, context):
+        raise error.ParseError(_('%r is not iterable of mappings')
+                               % pycompat.bytestr(self._value))
+
+    def join(self, context, mapping, sep):
+        return joinitems(pycompat.iterbytestr(self._value), sep)
+
+    def show(self, context, mapping):
+        return self._value
+
+    def tovalue(self, context, mapping):
+        return self._value
+
+class wrappedvalue(wrapped):
+    """Generic wrapper for pure non-list/dict/bytes value"""
+
+    def __init__(self, value):
+        self._value = value
+
+    def itermaps(self, context):
+        raise error.ParseError(_('%r is not iterable of mappings')
+                               % self._value)
+
+    def join(self, context, mapping, sep):
+        raise error.ParseError(_('%r is not iterable') % self._value)
+
+    def show(self, context, mapping):
+        return pycompat.bytestr(self._value)
+
+    def tovalue(self, context, mapping):
+        return self._value
+
 # stub for representing a date type; may be a real date type that can
 # provide a readable string value
 class date(object):
@@ -447,6 +485,20 @@  def evalrawexp(context, mapping, arg):
     func, data = arg
     return func(context, mapping, data)
 
+def evalwrapped(context, mapping, arg):
+    """Evaluate given argument to wrapped object"""
+    thing = evalrawexp(context, mapping, arg)
+    return makewrapped(context, mapping, thing)
+
+def makewrapped(context, mapping, thing):
+    """Lift object to a wrapped type"""
+    if isinstance(thing, wrapped):
+        return thing
+    thing = _unthunk(context, mapping, thing)
+    if isinstance(thing, bytes):
+        return wrappedbytes(thing)
+    return wrappedvalue(thing)
+
 def evalfuncarg(context, mapping, arg):
     """Evaluate given argument as value type"""
     return unwrapvalue(context, mapping, evalrawexp(context, mapping, arg))