# HG changeset patch # User Yuya Nishihara # Date 1521557786 -32400 # Node ID 7824783a6d5e780f2b4cf38c9ae13943a84aeb93 # Parent d48b80d588489009732687658219b1f378d9111a 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. diff -r d48b80d58848 -r 7824783a6d5e mercurial/templater.py --- 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. diff -r d48b80d58848 -r 7824783a6d5e mercurial/templateutil.py --- 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))