formatter: add function to convert dict to appropriate format
authorYuya Nishihara <yuya@tcha.org>
Mon, 15 Aug 2016 12:58:33 +0900
changeset 29794 4891f3b93182
parent 29793 24991e7f775f
child 29795 142ae01820a3
formatter: add function to convert dict to appropriate format This will be used to process key-value pairs by formatter. The default field names and format are derived from the {extras} template keyword. Tests will be added later.
mercurial/formatter.py
--- a/mercurial/formatter.py	Mon Aug 15 17:17:39 2016 +0900
+++ b/mercurial/formatter.py	Mon Aug 15 12:58:33 2016 +0900
@@ -51,6 +51,12 @@
         '''convert date tuple to appropriate format'''
         return date
     @staticmethod
+    def formatdict(data, key='key', value='value', fmt='%s=%s', sep=' '):
+        '''convert dict or key-value pairs to appropriate dict format'''
+        # use plain dict instead of util.sortdict so that data can be
+        # serialized as a builtin dict in pickle output
+        return dict(data)
+    @staticmethod
     def formatlist(data, name, fmt='%s', sep=' '):
         '''convert iterable to appropriate list format'''
         return list(data)
@@ -75,6 +81,12 @@
         if self._item is not None:
             self._showitem()
 
+def _iteritems(data):
+    '''iterate key-value pairs in stable order'''
+    if isinstance(data, dict):
+        return sorted(data.iteritems())
+    return data
+
 class plainformatter(baseformatter):
     '''the default text output scheme'''
     def __init__(self, ui, topic, opts):
@@ -92,6 +104,10 @@
         '''stringify date tuple in the given format'''
         return util.datestr(date, fmt)
     @staticmethod
+    def formatdict(data, key='key', value='value', fmt='%s=%s', sep=' '):
+        '''stringify key-value pairs separated by sep'''
+        return sep.join(fmt % (k, v) for k, v in _iteritems(data))
+    @staticmethod
     def formatlist(data, name, fmt='%s', sep=' '):
         '''stringify iterable separated by sep'''
         return sep.join(fmt % e for e in data)
@@ -129,7 +145,11 @@
         self._ui.write(pickle.dumps(self._data))
 
 def _jsonifyobj(v):
-    if isinstance(v, (list, tuple)):
+    if isinstance(v, dict):
+        xs = ['"%s": %s' % (encoding.jsonescape(k), _jsonifyobj(u))
+              for k, u in sorted(v.iteritems())]
+        return '{' + ', '.join(xs) + '}'
+    elif isinstance(v, (list, tuple)):
         return '[' + ', '.join(_jsonifyobj(e) for e in v) + ']'
     elif v is None:
         return 'null'
@@ -175,6 +195,14 @@
         g = self._t(self._topic, ui=self._ui, **self._item)
         self._ui.write(templater.stringify(g))
     @staticmethod
+    def formatdict(data, key='key', value='value', fmt='%s=%s', sep=' '):
+        '''build object that can be evaluated as either plain string or dict'''
+        data = util.sortdict(_iteritems(data))
+        def f():
+            yield plainformatter.formatdict(data, key, value, fmt, sep)
+        return templatekw._hybrid(f(), data, lambda k: {key: k, value: data[k]},
+                                  lambda d: fmt % (d[key], d[value]))
+    @staticmethod
     def formatlist(data, name, fmt='%s', sep=' '):
         '''build object that can be evaluated as either plain string or list'''
         # name is mandatory argument for now, but it could be optional if