registrar: add templatefunc to mark a function as template function (API)
authorFUJIWARA Katsunori <foozy@lares.dti.ne.jp>
Wed, 30 Mar 2016 02:10:44 +0900
changeset 28695 cc103bd0dbf9
parent 28694 9a6fa1d93bc8
child 28696 efa192203623
registrar: add templatefunc to mark a function as template function (API) This patch also adds loadfunction() to templater, because this combination helps to figure out how they cooperate with each other. Listing up loadfunction() in dispatch.extraloaders causes implicit loading template function at loading (3rd party) extension. This patch explicitly tests whether templatefunc decorator works as expected, because there is no bundled extension, which defines template function. This change requires that "templatefunc" attribute of (3rd party) extension is registrar.templatefunc or so.
mercurial/dispatch.py
mercurial/registrar.py
mercurial/templater.py
tests/test-command-template.t
--- a/mercurial/dispatch.py	Wed Mar 30 02:10:44 2016 +0900
+++ b/mercurial/dispatch.py	Wed Mar 30 02:10:44 2016 +0900
@@ -37,6 +37,7 @@
     revset,
     templatefilters,
     templatekw,
+    templater,
     ui as uimod,
     util,
 )
@@ -768,6 +769,7 @@
     ('filesetpredicate', fileset, 'loadpredicate'),
     ('revsetpredicate', revset, 'loadpredicate'),
     ('templatefilter', templatefilters, 'loadfilter'),
+    ('templatefunc', templater, 'loadfunction'),
     ('templatekeyword', templatekw, 'loadkeyword'),
 ]
 
--- a/mercurial/registrar.py	Wed Mar 30 02:10:44 2016 +0900
+++ b/mercurial/registrar.py	Wed Mar 30 02:10:44 2016 +0900
@@ -216,3 +216,29 @@
 
     Otherwise, explicit 'templatefilters.loadkeyword()' is needed.
     """
+
+class templatefunc(_templateregistrarbase):
+    """Decorator to register template function
+
+    Usage::
+
+        templatefunc = registrar.templatefunc()
+
+        @templatefunc('myfunc(arg1, arg2[, arg3])')
+        def myfuncfunc(context, mapping, args):
+            '''Explanation of this template function ....
+            '''
+            pass
+
+    The first string argument is used also in online help.
+
+    'templatefunc' instance in example above can be used to
+    decorate multiple functions.
+
+    Decorated functions are registered automatically at loading
+    extension, if an instance named as 'templatefunc' is used for
+    decorating in extension.
+
+    Otherwise, explicit 'templater.loadfunction()' is needed.
+    """
+    _getname = _funcregistrarbase._parsefuncdecl
--- a/mercurial/templater.py	Wed Mar 30 02:10:44 2016 +0900
+++ b/mercurial/templater.py	Wed Mar 30 02:10:44 2016 +0900
@@ -1069,5 +1069,11 @@
 
     raise RuntimeError("No hgweb templates found in %r" % paths)
 
+def loadfunction(ui, extname, registrarobj):
+    """Load template function from specified registrarobj
+    """
+    for name, func in registrarobj._table.iteritems():
+        funcs[name] = func
+
 # tell hggettext to extract docstrings from these functions:
 i18nfunctions = funcs.values()
--- a/tests/test-command-template.t	Wed Mar 30 02:10:44 2016 +0900
+++ b/tests/test-command-template.t	Wed Mar 30 02:10:44 2016 +0900
@@ -3693,3 +3693,26 @@
   [255]
 
   $ cd ..
+
+Test that template function in extension is registered as expected
+
+  $ cd a
+
+  $ cat <<EOF > $TESTTMP/customfunc.py
+  > from mercurial import registrar
+  > 
+  > templatefunc = registrar.templatefunc()
+  > 
+  > @templatefunc('custom()')
+  > def custom(context, mapping, args):
+  >     return 'custom'
+  > EOF
+  $ cat <<EOF > .hg/hgrc
+  > [extensions]
+  > customfunc = $TESTTMP/customfunc.py
+  > EOF
+
+  $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
+  custom
+
+  $ cd ..