Commits

Eric Knibbe committed 395b8e8 Draft

numerous improvements bringing the Lasso domain to a workable state

  • Participants
  • Parent commits ecf1e67

Comments (0)

Files changed (8)

File python/lassodomain/LICENSE

+If not otherwise noted, the extensions in this package are licensed
+under the following license.
+
+Copyright (c) 2013 by the contributors (see README file).
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File python/lassodomain/MANIFEST.in

+include README.*
+include LICENSE
+include CHANGES.*

File python/lassodomain/README.rst

 About
 =====
 
-This extension adds a Lasso domain to Sphinx. It is currently a somewhat
-functional work in progress.
+This extension adds support for the Lasso language to Sphinx.
+
+The following objects are supported:
+
+* Unbound method
+* Trait
+
+  * Require
+  * Provide
+
+* Type/Thread
+
+  * Member method
+  * Provide
+
+Methods are associated with their type or trait using the arrow operator::
+
+	Type->member_method
 
 
 Usage
 =====
 
-After installing lassodomain.py in site-packages/sphinxcontrib, add the
-extension to your list of extensions in conf.py::
+After installing :file:`lassodomain.py` in `site-packages/sphinxcontrib`, add the
+:mod:`sphinxcontrib.lassodomain` extension to the :data:`extensions` list in
+your Sphinx configuration file (:file:`conf.py`)::
 
-  extensions = ['sphinx.ext.autodoc', 'sphinxcontrib.lassodomain']
+  extensions = ['sphinxcontrib.lassodomain']
 
 Also, if your project is primarily Lasso, you'll want to define the primary
 domain as well::
 
   primary_domain = 'ls'
 
-
-Directives and Roles
-====================
-
-This domain provides method, type, trait, thread, provide, and require
-directives, as well as meth, trait, type, and thread roles for 
-cross-referencing. To link to a member method, use member tag syntax, such as 
-``:meth:`Bytes->getrange```.
-
-.. add more examples here

File python/lassodomain/setup.cfg

+[egg_info]
+tag_build = dev
+tag_date = true
+
+[aliases]
+release = egg_info -RDb ''

File python/lassodomain/setup.py

+# -*- coding: utf-8 -*-
+
+from setuptools import setup, find_packages
+
+long_desc = '''
+This package contains the lassodomain Sphinx extension.
+
+.. add description here ..
+'''
+
+requires = ['Sphinx>=0.6']
+
+setup(
+    name='sphinxcontrib-lassodomain',
+    version='0.1',
+    url='http://bitbucket.org/birkenfeld/sphinx-contrib',
+    download_url='http://pypi.python.org/pypi/sphinxcontrib-lassodomain',
+    license='BSD',
+    author='Eric Knibbe',
+    author_email='eric@lassosoft.com',
+    description='Sphinx "lassodomain" extension',
+    long_description=long_desc,
+    zip_safe=False,
+    classifiers=[
+        'Development Status :: 4 - Beta',
+        'Environment :: Console',
+        'Environment :: Web Environment',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: BSD License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Topic :: Documentation',
+        'Topic :: Utilities',
+    ],
+    platforms='any',
+    packages=find_packages(),
+    include_package_data=True,
+    install_requires=requires,
+    namespace_packages=['sphinxcontrib'],
+)

File python/lassodomain/sphinxcontrib/__init__.py

+# -*- coding: utf-8 -*-
+"""
+    sphinxcontrib
+    ~~~~~~~~~~~~~
+
+    This package is a namespace package that contains all extensions
+    distributed in the ``sphinx-contrib`` distribution.
+
+    :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+__import__('pkg_resources').declare_namespace(__name__)
+

File python/lassodomain/sphinxcontrib/lassodomain.py

 
 
 class LSObject(ObjectDescription):
-    """
-    Description of a Lasso object.
+    """Description of a Lasso object.
     """
     doc_field_types = [
         # :param name: description
         TypedField('parameter', label=l_('Parameters'), can_collapse=True,
                    names=('param', 'parameter'), typerolename='obj',
                    typenames=('ptype', 'paramtype', 'type')),
-        # :return: description (if no return type specified)
-        Field('return', label=l_('Returns'), has_arg=False,
+        # :return: description
+        Field('returnvalue', label=l_('Returns'), has_arg=False,
               names=('return', 'returns')),
-        # :returnas typename: description (if return type is specified)
-        Field('returnas', label=l_('Returns as'), has_arg=True,
-              names=('returnas','returnsas')),
+        # :rtype: typename
+        Field('returntype', label=l_('Return type'), has_arg=False,
+              names=('rtype', 'returntype')),
+        # :author: name
+        Field('author', label=l_('Author'), has_arg=False,
+              names=('author', 'authors')),
         # :see: resource
         Field('seealso', label=l_('See also'), has_arg=False,
               names=('see', 'url')),
         # :parent: typename
-        Field('parent', label=l_('Parent'), has_arg=False,
-              names=('parent')),
-        # :import: trait_1, trait_2
+        Field('parent', label=l_('Parent type'), has_arg=False,
+              names=('parent', 'super')),
+        # :import: trait_name
         Field('import', label=l_('Imports'), has_arg=False,
               names=('import', 'imports')),
     ]
 
-    def get_signature_prefix(self, sig):
-        """May return a prefix to put before the object name in the
-        signature.
-        """
-        return ''
-
     def needs_arglist(self):
         """May return true if an empty argument list is to be generated even if
         the document contains none.
         """
         return False
 
+    def get_signature_prefix(self, sig):
+        """May return a prefix to put before the object name in the signature.
+        """
+        return ''
+
+    def get_index_text(self, objectname, name_obj):
+        """Return the text for the index entry of the object.
+        """
+        raise NotImplementedError('must be implemented in subclasses')
+
     def handle_signature(self, sig, signode):
+        """Transform a Lasso signature into RST nodes.
+        """
         sig = sig.strip()
-        if '(' in sig and sig[-1:] == ')':
+        if '(' in sig:
+            if ')::' in sig:
+                sig, returntype = sig.rsplit('::', 1)
+            else:
+                returntype = None
             prefix, arglist = sig.split('(', 1)
             prefix = prefix.strip()
             arglist = arglist[:-1].strip()
         else:
+            if '::' in sig:
+                sig, returntype = sig.rsplit('::', 1)
+            else:
+                returntype = None
             prefix = sig
             arglist = None
         if '->' in prefix:
-            nameprefix, name = prefix.rsplit('->', 1)
+            name_prefix, name = prefix.rsplit('->', 1)
         else:
-            nameprefix = None
+            name_prefix = None
             name = prefix
 
         objectname = self.env.temp_data.get('ls:object')
-        if nameprefix:
-            #if objectname:
-                # if an object has been set on the page and the item name
-                # includes a prefix, ignore the page object
-                #nameprefix = objectname + '->' + nameprefix
-            fullname = nameprefix + '->' + name
+        if name_prefix:
+            fullname = name_prefix + '->' + name
         elif objectname:
             fullname = objectname + '->' + name
         else:
-            # no current object set and no prefix, denoting an unbound method
             objectname = ''
             fullname = name
 
         sig_prefix = self.get_signature_prefix(sig)
         if sig_prefix:
             signode += addnodes.desc_annotation(sig_prefix, sig_prefix)
-
-        if nameprefix:
-            signode += addnodes.desc_addname(nameprefix + '->',
-                                             nameprefix + '->')
+        if name_prefix:
+            name_prefix += '->'
+            signode += addnodes.desc_addname(name_prefix, name_prefix)
         signode += addnodes.desc_name(name, name)
         if self.needs_arglist():
             if not arglist:
-                signode += addnodes.desc_parameterlist()    # add empty signature
+                signode += addnodes.desc_parameterlist()
             else:
-                _pseudo_parse_arglist(signode, arglist)     # from the python domain
-        return fullname, nameprefix
+                _pseudo_parse_arglist(signode, arglist)
+            if returntype:
+                signode += addnodes.desc_returns(returntype, returntype)
+        return fullname, name_prefix
 
     def add_target_and_index(self, name_obj, sig, signode):
-        objectname = self.options.get(
-            'object', self.env.temp_data.get('ls:object'))
         fullname = name_obj[0]
+        objectname = self.env.temp_data.get('ls:object')
         if fullname not in self.state.document.ids:
             signode['names'].append(fullname)
             signode['ids'].append(fullname)
-            signode['first'] = not self.names
+            signode['first'] = (not self.names)
             self.state.document.note_explicit_target(signode)
             objects = self.env.domaindata['ls']['objects']
             if fullname in objects:
                 self.state_machine.reporter.warning(
                     'duplicate object description of %s, ' % fullname +
                     'other instance in ' +
-                    self.env.doc2path(objects[fullname][0]),
+                    self.env.doc2path(objects[fullname][0]) +
+                    ', use :noindex: for one of them',
                     line=self.lineno)
             objects[fullname] = self.env.docname, self.objtype
 
             self.indexnode['entries'].append(('single', indextext,
                                               fullname, ''))
 
-    def get_index_text(self, objectname, name_obj):
-        name, obj = name_obj
-        if self.objtype == 'method':
-            if not obj:
-                return _('%s') % name
-            return _('%s->%s') % (obj, name)
-        elif self.objtype == 'provide':
-            return _('%s->%s') % (obj, name)
-        return _('%s (%s)') % (name, self.objtype)
+    def before_content(self):
+        # needed for automatic qualification of members (reset in subclasses)
+        self.objname_set = False
+
+    def after_content(self):
+        if self.objname_set:
+            self.env.temp_data['ls:object'] = None
 
 
 class LSDefinition(LSObject):
-    """Description of an object definition (types, traits, threads)."""
+    """Description of an object definition (type, trait, thread).
+    """
     def get_signature_prefix(self, sig):
         return self.objtype + ' '
 
+    def get_index_text(self, objectname, name_obj):
+        return _('%s (%s)') % (name_obj[0], self.objtype)
 
-class LSCallable(LSObject):
-    """Description of an object with a signature."""
+    def before_content(self):
+        LSObject.before_content(self)
+        if self.names:
+            self.env.temp_data['ls:object'] = self.names[0][0]
+            self.objname_set = True
+
+
+class LSTag(LSObject):
+    """Description of an object with a signature (method, member).
+    """
     def needs_arglist(self):
         return True
 
+    def get_index_text(self, objectname, name_obj):
+        name = name_obj[0].split('->')[-1]
+        if not (objectname or name_obj[1]):
+            return _('%s() (method)') % name
+        else:
+            objectname = name_obj[0].split('->')[0]
+        return _('%s() (%s member)') % (name, objectname)
 
-class LSTraitTag(LSCallable):
-    """Description of an object within a trait."""
+
+class LSTraitTag(LSTag):
+    """Description of a tag within a trait (require, provide).
+    """
     def get_signature_prefix(self, sig):
         return self.objtype + ' '
 
+    def get_index_text(self, objectname, name_obj):
+        name = name_obj[0].split('->')[-1]
+        return _('%s() (%s %s)') % (name, objectname, self.objtype)
+
 
 class LSXRefRole(XRefRole):
-    """
-    Provides cross reference links for Lasso objects.
+    """Provides cross reference links for Lasso objects.
     """
     def process_link(self, env, refnode, has_explicit_title, title, target):
         refnode['ls:object'] = env.temp_data.get('ls:object')
 
 
 class LassoDomain(Domain):
-    """
-    Lasso language domain.
+    """Lasso language domain.
     """
     name = 'ls'
     label = 'Lasso'
     object_types = {
-        'method':  ObjType(l_('method'),  'meth', 'obj'),
-        'trait':   ObjType(l_('trait'),   'trait', 'obj'),
-        'type':    ObjType(l_('type'),    'type', 'obj'),
-        'thread':  ObjType(l_('thread'),  'thread', 'obj'),
-        'provide': ObjType(l_('provide'), 'meth', 'obj'),
-        'require': ObjType(l_('require'), 'meth', 'obj'),
+        'method':  ObjType(l_('method'),  'meth'),
+        'member':  ObjType(l_('member'),  'meth'),
+        'provide': ObjType(l_('provide'), 'meth'),
+        'require': ObjType(l_('require'), 'meth'),
+        'type':    ObjType(l_('type'),    'type'),
+        'trait':   ObjType(l_('trait'),   'trait'),
+        'thread':  ObjType(l_('thread'),  'thread'),
     }
     directives = {
-        'method':  LSCallable,
+        'method':  LSTag,
+        'member':  LSTag,
+        'provide': LSTraitTag,
+        'require': LSTraitTag,  # name and signature only
         'type':    LSDefinition,
         'trait':   LSDefinition,
         'thread':  LSDefinition,
-        'provide': LSTraitTag,
-        'require': LSTraitTag,  # name and signature only
     }
     roles = {
         'meth':   LSXRefRole(fix_parens=True),
+        'type':   LSXRefRole(),
         'trait':  LSXRefRole(),
-        'type':   LSXRefRole(),
         'thread': LSXRefRole(),
     }
     initial_data = {

File python/lassodomain/tox.ini

+## configuration for tox <http://codespeak.net/tox/>
+
+## tox automates running certain tasks within virtualenvs.  The following
+## tox configuration outlines a basic setup for running unit tests and
+## building sphinx docs in separate virtual environments.  Give it a try!
+
+[tox]
+envlist=python,doc
+
+# test running
+[testenv:python]
+deps=
+    ## if you use nose for test running
+    # nose
+    ## if you use py.test for test running
+    # pytest
+commands=
+    ## run tests with py.test
+    # py.test []
+    ## run tests with nose
+    # nose
+
+[testenv:doc]
+deps=
+    sphinx
+    # add all Sphinx extensions and other dependencies required to build your docs
+commands=
+    ## test links
+    # sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees doc {envtmpdir}/linkcheck
+    ## test html output
+    # sphinx-build -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html
+