Commits

togakushi  committed cf29a49

v0.0.2 Released

  • Participants
  • Parent commits 0b7384d

Comments (0)

Files changed (5)

 --------------------------
 
 * Initial version.
+
+Version 0.0.2 (2012-10-05)
+--------------------------
+
+* Add a directive to indicate the use of name ``howto``
+* bug fix
 
    :op:command:`zzzz`
 
+::
+
+  .. op:howto:: yyyy
+
+  :op:howto:`yyyy`
 
 Install
 =======
 
 setup(
     name='sphinxcontrib-operationdomain',
-    version='0.1',
+    version='0.0.2',
     url='http://bitbucket.org/togakushi/sphinx-contrib',
     download_url='http://pypi.python.org/pypi/sphinxcontrib-erlangdomain',
     license='BSD',

File sphinxcontrib/op.py

     r'''^ ([\w.]*\.)?            # class name(s)
           (\w+)  \s*             # thing name
           (?: \((.*)\)           # optional: arguments
-           (?:\s* -> \s* (.*))?  #           return annotation
           )? $                   # and nothing more
           ''', re.VERBOSE)
 
         'noindex': directives.flag,
         'command': directives.unchanged,
         'setting': directives.unchanged,
-        'annotation': directives.unchanged,
+        'howto': directives.unchanged,
     }
 
     doc_field_types = [
         # determine command and class name (if applicable), as well as full name
         modname = self.options.get('command', self.env.temp_data.get('op:command'))
         setname = self.options.get('setting', self.env.temp_data.get('op:setting'))
+        howname = self.options.get('howto', self.env.temp_data.get('op:howto'))
 
         add_command = True
         if name_prefix:
 
         signode['command'] = modname
         signode['setting'] = setname
+        signode['howto'] = setname
         signode['fullname'] = fullname
 
         sig_prefix = self.get_signature_prefix(sig)
         # exceptions are a special case, since they are documented in the
         # 'exceptions' command.
         elif add_command and self.env.config.add_command_names:
-            modname = self.options.get(
-                'command', self.env.temp_data.get('op:command'))
-            setname = self.options.get(
-                'setting', self.env.temp_data.get('op:setting'))
+            modname = self.options.get('command', self.env.temp_data.get('op:command'))
+            setname = self.options.get('setting', self.env.temp_data.get('op:setting'))
+            howname = self.options.get('howto', self.env.temp_data.get('op:howto'))
             nodetext = modname + '.'
             signode += addnodes.desc_addname(nodetext, nodetext)
 
-        anno = self.options.get('annotation')
-
         signode += addnodes.desc_name(name, name)
         if not arglist:
             if self.needs_arglist():
                 signode += addnodes.desc_parameterlist()
             if retann:
                 signode += addnodes.desc_returns(retann, retann)
-            if anno:
-                signode += addnodes.desc_annotation(' ' + anno, ' ' + anno)
             return fullname, name_prefix
 
         if retann:
             signode += addnodes.desc_returns(retann, retann)
-        if anno:
-            signode += addnodes.desc_annotation(' ' + anno, ' ' + anno)
         return fullname, name_prefix
 
     def get_index_text(self, modname, name):
         raise NotImplementedError('must be implemented in subclasses')
 
     def add_target_and_index(self, name_cls, sig, signode):
-        modname = self.options.get(
-            'command', self.env.temp_data.get('op:command'))
-        setname = self.options.get(
-            'setting', self.env.temp_data.get('op:setting'))
+        modname = self.options.get('command', self.env.temp_data.get('op:command'))
+        setname = self.options.get('setting', self.env.temp_data.get('op:setting'))
+        howname = self.options.get('howto', self.env.temp_data.get('op:howto'))
         fullname = (modname and modname + '.' or '') + name_cls[0]
         # note target
         if fullname not in self.state.document.ids:
                                               fullname, ''))
 
 
+class OperationXRefRole(XRefRole):
+    def process_link(self, env, refnode, has_explicit_title, title, target):
+        refnode['op:command'] = env.temp_data.get('op:command')
+        refnode['op:setting'] = env.temp_data.get('op:setting')
+        refnode['op:howto'] = env.temp_data.get('op:howto')
+        if not has_explicit_title:
+            title = title.lstrip('.')   # only has a meaning for the target
+            target = target.lstrip('~') # only has a meaning for the title
+            # if the first character is a tilde, don't display the command/class
+            # parts of the contents
+            if title[0:1] == '~':
+                title = title[1:]
+                dot = title.rfind('.')
+                if dot != -1:
+                    title = title[dot+1:]
+        # if the first character is a dot, search more specific namespaces first
+        # else search builtins first
+        if target[0:1] == '.':
+            target = target[1:]
+            refnode['refspecific'] = True
+        return title, target
+
+
 class OperationCommand(Directive):
     """
     Directive to mark description of a new command.
         return ret
 
 
+class OperationCommandIndex(Index):
+    """
+    Index subclass to provide the Operation command index.
+    """
+
+    name = 'commandindex'
+    localname = l_('Command Index')
+    shortname = l_('Command')
+
+    def generate(self, docnames=None):
+        content = {}
+        # list of all commands, sorted by command name
+        commands = sorted(self.domain.data['commands'].iteritems(),
+                         key=lambda x: x[0].lower())
+        # sort out collapsable commands
+        prev_comname = ''
+        num_toplevels = 0
+        for comname, (docname, synopsis, platforms, deprecated) in commands:
+            entries = content.setdefault(comname[0].lower(), [])
+
+            package = comname.split('.')[0]
+            if package != comname:
+                # it's a subentries
+                if prev_comname == package:
+                    # first subentries - make parent a group head
+                    if entries:
+                        entries[-1][1] = 1
+                elif not prev_comname.startswith(package):
+                    # subentries without parent in list, add dummy entry
+                    entries.append([package, 1, '', '', '', '', ''])
+                subtype = 2
+                entriename = comname.split(package + '.', 1)[1]
+            else:
+                num_toplevels += 1
+                subtype = 0
+                entriename = comname
+
+            qualifier = deprecated and _('Deprecated') or ''
+            entries.append([entriename, subtype, docname,
+                            'command-' + comname, platforms, qualifier, synopsis])
+            prev_comname = comname
+
+        # apply heuristics when to collapse modindex at page load:
+        # only collapse if number of toplevel commands is larger than
+        # number of submodules
+        collapse = len(commands) - num_toplevels < num_toplevels
+
+        # sort by first letter
+        content = sorted(content.iteritems())
+
+        return content, collapse
+
+
 class OperationSetting(Directive):
     """
     Directive to mark description of a new setting.
         return ret
 
 
-class OperationXRefRole(XRefRole):
-    def process_link(self, env, refnode, has_explicit_title, title, target):
-        refnode['op:command'] = env.temp_data.get('op:command')
-        refnode['op:setting'] = env.temp_data.get('op:setting')
-        if not has_explicit_title:
-            title = title.lstrip('.')   # only has a meaning for the target
-            target = target.lstrip('~') # only has a meaning for the title
-            # if the first character is a tilde, don't display the command/class
-            # parts of the contents
-            if title[0:1] == '~':
-                title = title[1:]
-                dot = title.rfind('.')
-                if dot != -1:
-                    title = title[dot+1:]
-        # if the first character is a dot, search more specific namespaces first
-        # else search builtins first
-        if target[0:1] == '.':
-            target = target[1:]
-            refnode['refspecific'] = True
-        return title, target
-
-
-class OperationCommandIndex(Index):
-    """
-    Index subclass to provide the Operation command index.
-    """
-
-    name = 'commandindex'
-    localname = l_('Command Index')
-    shortname = l_('Command')
-
-    def generate(self, docnames=None):
-        content = {}
-        # list of prefixes to ignore
-        ignores = self.domain.env.config['modindex_common_prefix']
-        ignores = sorted(ignores, key=len, reverse=True)
-        # list of all commands, sorted by command name
-        commands = sorted(self.domain.data['commands'].iteritems(),
-                         key=lambda x: x[0].lower())
-        # sort out collapsable commands
-        prev_comname = ''
-        num_toplevels = 0
-        for comname, (docname, synopsis, platforms, deprecated) in commands:
-            if docnames and docname not in docnames:
-                continue
-
-            for ignore in ignores:
-                if comname.startswith(ignore):
-                    comname = comname[len(ignore):]
-                    stripped = ignore
-                    break
-            else:
-                stripped = ''
-
-            # we stripped the whole command name?
-            if not comname:
-                comname, stripped = stripped, ''
-
-            entries = content.setdefault(comname[0].lower(), [])
-
-            package = comname.split('.')[0]
-            if package != comname:
-                # it's a subcommand
-                if prev_comname == package:
-                    # first subcommand - make parent a group head
-                    if entries:
-                        entries[-1][1] = 1
-                elif not prev_comname.startswith(package):
-                    # subcommand without parent in list, add dummy entry
-                    entries.append([stripped + package, 1, '', '', '', '', ''])
-                subtype = 2
-            else:
-                num_toplevels += 1
-                subtype = 0
-
-            qualifier = deprecated and _('Deprecated') or ''
-            entries.append([stripped + comname, subtype, docname,
-                            'command-' + stripped + comname, platforms,
-                            qualifier, synopsis])
-            prev_comname = comname
-
-        # apply heuristics when to collapse modindex at page load:
-        # only collapse if number of toplevel commands is larger than
-        # number of submodules
-        collapse = len(commands) - num_toplevels < num_toplevels
-
-        # sort by first letter
-        content = sorted(content.iteritems())
-
-        return content, collapse
-
-
 class OperationSettingIndex(Index):
     """
-    Index subclass to provide the Operation command index.
+    Index subclass to provide the Operation Seting index.
     """
 
     name = 'settingindex'
 
     def generate(self, docnames=None):
         content = {}
-        # list of prefixes to ignore
-        ignores = self.domain.env.config['modindex_common_prefix']
-        ignores = sorted(ignores, key=len, reverse=True)
-        # list of all setting, sorted by command name
+        # list of all setting, sorted by setting name
         settings = sorted(self.domain.data['settings'].iteritems(),
                          key=lambda x: x[0].lower())
         # sort out collapsable setting
         prev_setname = ''
         num_toplevels = 0
         for setname, (docname, synopsis, platforms, deprecated) in settings:
-            if docnames and docname not in docnames:
-                continue
-
-            for ignore in ignores:
-                if setname.startswith(ignore):
-                    setname = setname[len(ignore):]
-                    stripped = ignore
-                    break
-            else:
-                stripped = ''
-
-            # we stripped the whole command name?
-            if not setname:
-                setname, stripped = stripped, ''
-
             entries = content.setdefault(setname[0].lower(), [])
 
             package = setname.split('.')[0]
             if package != setname:
-                # it's a subcommand
+                # it's a subentries
                 if prev_setname == package:
-                    # first subcommand - make parent a group head
+                    # first subentries - make parent a group head
                     if entries:
                         entries[-1][1] = 1
                 elif not prev_setname.startswith(package):
-                    # subcommand without parent in list, add dummy entry
-                    entries.append([stripped + package, 1, '', '', '', '', ''])
+                    # subentries without parent in list, add dummy entry
+                    entries.append([package, 1, '', '', '', '', ''])
                 subtype = 2
+                entriename = setname.split(package + '.', 1)[1]
             else:
                 num_toplevels += 1
                 subtype = 0
+                entriename = setname
 
             qualifier = deprecated and _('Deprecated') or ''
-            entries.append([stripped + setname, subtype, docname,
-                            'setting-' + stripped + setname, platforms,
-                            qualifier, synopsis])
+            entries.append([entriename, subtype, docname,
+                            'setting-' + setname, platforms, qualifier, synopsis])
             prev_setname = setname
 
         # apply heuristics when to collapse modindex at page load:
         return content, collapse
 
 
+class OperationHowto(Directive):
+    """
+    Directive to mark description of a new howto.
+    """
+
+    has_content = False
+    required_arguments = 1
+    optional_arguments = 0
+    final_argument_whitespace = True
+    option_spec = {
+        'platform': lambda x: x,
+        'synopsis': lambda x: x,
+        'noindex': directives.flag,
+        'deprecated': directives.flag,
+    }
+
+    def run(self):
+        env = self.state.document.settings.env
+        howname = self.arguments[0].strip()
+        noindex = 'noindex' in self.options
+        env.temp_data['op:howto'] = howname
+        ret = []
+        if not noindex:
+            env.domaindata['op']['howtos'][howname] = \
+                (env.docname, self.options.get('synopsis', ''),
+                 self.options.get('platform', ''), 'deprecated' in self.options)
+            # make a duplicate entry in 'objects' to facilitate searching for
+            # the howto in OperationDomain.find_obj()
+            env.domaindata['op']['objects'][howname] = (env.docname, 'howto')
+            targetnode = nodes.target('', '', ids=['howto-' + howname], ismod=True)
+            self.state.document.note_explicit_target(targetnode)
+            # the platform and synopsis aren't printed; in fact, they are only
+            # used in the modindex currently
+            ret.append(targetnode)
+            indextext = _('%s (howto)') % howname
+            inode = addnodes.index(entries=[('single', indextext, 'howto-' + howname, '')])
+            ret.append(inode)
+        return ret
+
+
+class OperationHowtoIndex(Index):
+    """
+    Index subclass to provide the Operation howto index.
+    """
+
+    name = 'howtoindex'
+    localname = l_('Howto Index')
+    shortname = l_('Howto')
+
+    def generate(self, docnames=None):
+        content = {}
+        # list of all howtos, sorted by howto name
+        howtos = sorted(self.domain.data['howtos'].iteritems(),
+                         key=lambda x: x[0].lower())
+        # sort out collapsable howtos
+        prev_howname = ''
+        num_toplevels = 0
+        for howname, (docname, synopsis, platforms, deprecated) in howtos:
+            entries = content.setdefault(howname[0].lower(), [])
+
+            package = howname.split('.')[0]
+            if package != howname:
+                # it's a subentries
+                if prev_howname == package:
+                    # first subentries - make parent a group head
+                    if entries:
+                        entries[-1][1] = 1
+                elif not prev_howname.startswith(package):
+                    # subentries without parent in list, add dummy entry
+                    entries.append([package, 1, '', '', '', '', ''])
+                subtype = 2
+                entriename = howname.split(package + '.', 1)[1]
+            else:
+                num_toplevels += 1
+                subtype = 0
+                entriename = howname
+
+            qualifier = deprecated and _('Deprecated') or ''
+            entries.append([entriename, subtype, docname,
+                            'howto-' + howname, platforms, qualifier, synopsis])
+            prev_howname = howname
+
+        # apply heuristics when to collapse modindex at page load:
+        # only collapse if number of toplevel howtos is larger than
+        # number of submodules
+        collapse = len(howtos) - num_toplevels < num_toplevels
+
+        # sort by first letter
+        content = sorted(content.iteritems())
+
+        return content, collapse
+
+
 class OperationDomain(Domain):
     """Operation domain."""
     name = 'op'
     object_types = {
         'command':       ObjType(l_('command'),        'command'),
         'setting':       ObjType(l_('setting'),        'setting'),
+        'howto':         ObjType(l_('howto'),           'howto'),
     }
 
     directives = {
         'command':         OperationCommand,
         'setting':         OperationSetting,
+        'howto':           OperationHowto,
     }
     roles = {
         'command':   OperationXRefRole(),
         'setting':   OperationXRefRole(),
+        'howto':   OperationXRefRole(),
     }
     initial_data = {
         'objects': {},  # fullname -> docname, objtype
-        'commands': {},  # comname -> docname, synopsis, platform, deprecated
-        'settings': {},  # setname -> docname, synopsis, platform, deprecated
+        'commands': {}, # modname -> modname, synopsis, platform, deprecated
+        'settings': {}, # setname -> setname, synopsis, platform, deprecated
+        'howtos': {},   # howname -> howname, synopsis, platform, deprecated
     }
     indices = [
         OperationCommandIndex,
         OperationSettingIndex,
+        OperationHowtoIndex,
     ]
 
     def clear_doc(self, docname):
         for setname, (fn, _, _, _) in self.data['settings'].items():
             if fn == docname:
                 del self.data['settings'][setname]
+        for howname, (fn, _, _, _) in self.data['howtos'].items():
+            if fn == docname:
+                del self.data['howtos'][howname]
 
-    def find_obj(self, env, modname, setname, name, type, searchmode=0):
+    def find_obj(self, env, modname, setname, howname, name, type, searchmode=0):
         """Find a Operation object for "name", perhaps using the given command
            Returns a list of (name, object entry) tuples.
         """
                      type, target, node, contnode):
         modname = node.get('op:command')
         setname = node.get('op:setting')
+        howname = node.get('op:howto')
         searchmode = node.hasattr('refspecific') and 1 or 0
-        matches = self.find_obj(env, modname, setname, target,
-                                type, searchmode)
+        matches = self.find_obj(env, modname, setname, howname, target, type, searchmode)
         if not matches:
             return None
         elif len(matches) > 1:
                 title += _(' (deprecated)')
             if platform:
                 title += ' (' + platform + ')'
-            return make_refnode(builder, fromdocname, docname,
-                                'command-' + name, contnode, title)
+            return make_refnode(builder, fromdocname, docname, 'command-' + name, contnode, title)
         elif obj[1] == 'setting':
             # get additional info for settings
             docname, synopsis, platform, deprecated = self.data['settings'][name]
                 title += _(' (deprecated)')
             if platform:
                 title += ' (' + platform + ')'
-            return make_refnode(builder, fromdocname, docname,
-                                'setting-' + name, contnode, title)
+            return make_refnode(builder, fromdocname, docname, 'setting-' + name, contnode, title)
+        elif obj[1] == 'howto':
+            # get additional info for howtos
+            docname, synopsis, platform, deprecated = self.data['howtos'][name]
+            assert docname == obj[0]
+            title = name
+            if synopsis:
+                title += ': ' + synopsis
+            if deprecated:
+                title += _(' (deprecated)')
+            if platform:
+                title += ' (' + platform + ')'
+            return make_refnode(builder, fromdocname, docname, 'howto-' + name, contnode, title)
         else:
             return make_refnode(builder, fromdocname, obj[0], name,
                                 contnode, name)
-
+                                
     def get_objects(self):
         for modname, info in self.data['commands'].iteritems():
             yield (modname, modname, 'command', info[0], 'command-' + modname, 0)
         for setname, info in self.data['settings'].iteritems():
-            yield (setname, setname, 'setting', info[0], 'setting-' + modname, 0)
+            yield (setname, setname, 'setting', info[0], 'setting-' + setname, 0)
+        for howname, info in self.data['howtos'].iteritems():
+            yield (howname, howname, 'howto', info[0], 'howto-' + howname, 0)
         for refname, (docname, type) in self.data['objects'].iteritems():
             yield (refname, refname, type, docname, refname, 1)
 

File test/test_doc.rst

 
 If all links are valid, test is done successfully.
 
-Test Case - setting Directiv
-============================
+Test Case - Directiv
+====================
 
 .. op:setting:: Test Case 1
 
+.. op:command:: Test Case 2
 
-Test Case - command Directiv
-============================
-
-.. op:command:: Test Case 2
+.. op:howto:: Test Case 3
 
 
 Test Case - Role
 :op:setting:`Test Case 1`
 
 :op:command:`Test Case 2`
+
+:op:howto:`Test Case 3`