[PATCH V2] commands: use a class as decorator to build table incrementally

Adrian Buehlmann adrian at cadifra.com
Wed May 11 17:29:07 CDT 2011


On 2011-05-11 23:55, Matt Mackall wrote:
> On Wed, 2011-05-11 at 23:48 +0200, Adrian Buehlmann wrote:
>> On 2011-05-11 20:34, Adrian Buehlmann wrote:
>>> # HG changeset patch
>>> # User Adrian Buehlmann <adrian at cadifra.com>
>>> # Date 1305097807 -7200
>>> # Node ID 7c9c95bbfb3bab2663f0512867dd9115753caede
>>> # Parent  c97d8485b5fa46c94b8afcfab0cde97629ba4086
>>> commands: use a class as decorator to build table incrementally
>>>
>>> this allows to define the table entries near the command function
>>>
>>> diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
>>> --- a/mercurial/cmdutil.py
>>> +++ b/mercurial/cmdutil.py
>>> @@ -1251,3 +1251,23 @@
>>>          raise util.Abort(_("empty commit message"))
>>>  
>>>      return text
>>> +
>>> +def command(table):
>>> +    '''returns a class bound to table that can be used as a decorator
>>> +    for populating that command table'''
>>> +
>>> +    class cmd(object):
>>> +        '''decorator for populating a command table'''
>>> +        def __init__(self, name, options, synopsis=None):
>>> +            self.name = name
>>> +            self.options = options
>>> +            self.synopsis = synopsis
>>> +
>>> +        def __call__(self, func):
>>> +            if self.synopsis:
>>> +                table[self.name] = func, self.options, self.synopsis
>>> +            else:
>>> +                table[self.name] = func, self.options
>>> +            return func
>>> +
>>> +    return cmd
>>> diff --git a/mercurial/commands.py b/mercurial/commands.py
>>> --- a/mercurial/commands.py
>>> +++ b/mercurial/commands.py
>>> @@ -10,15 +10,129 @@
>>>  from i18n import _, gettext
>>>  import os, re, sys, difflib, time, tempfile
>>>  import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
>>> -import patch, help, url, encoding, templatekw, discovery
>>> +import patch, help, url, encoding, templatekw, discovery, cmdutil
>>>  import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
>>                                  ^^^^^^^
>> Bah. Stupid me. cmdutil is already there.
>>
>> Will resend.
> 
> We're having a bit of a discussion on IRC about whether writing the
> decorator as a nested function as a class or a nested function is
> better.
> 
> My leaning is that since the methods for these decorator classes are
> always just __init__ and __call__ and will never be more than that, the
> class model is just an obfuscation of the nested function style, rather
> than a useful abstraction in its own right.
> 
> But I think the rest of it is fine at this point.
> 

Ok. So the winner is: Martin's pattern, but binding it to a table via
another outer function, so it can be reused for extensions:

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1251,3 +1251,15 @@
         raise util.Abort(_("empty commit message"))

     return text
+
+def command(table):
+    '''returns a function object bound to table which can be used as
+    a decorator for populating table as a command table'''
+
+    def cmd(name, options, synopsis):
+        def decorator(func):
+            table[name] = (func, options, synopsis)
+            return func
+        return decorator
+
+    return cmd

For me internally (in my limited brain), I need the class model for
thinking, but I can map it to the Martin pattern ;-)

Full patch in ~10 hours.

Thanks to all.




More information about the Mercurial-devel mailing list