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.
--- a/mercurial/templater.py Wed Apr 04 21:06:14 2018 +0900
+++ b/mercurial/templater.py Tue Mar 20 23:56:26 2018 +0900
@@ -32,6 +32,9 @@
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.
--- a/mercurial/templateutil.py Wed Apr 04 21:06:14 2018 +0900
+++ b/mercurial/templateutil.py Tue Mar 20 23:56:26 2018 +0900
@@ -66,6 +66,44 @@
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 @@
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))