Merge branch 'release' of git://github.com/melinath/philo
authorJoseph Spiros <joseph.spiros@ithinksw.com>
Wed, 25 May 2011 21:55:26 +0000 (17:55 -0400)
committerJoseph Spiros <joseph.spiros@ithinksw.com>
Wed, 25 May 2011 21:55:26 +0000 (17:55 -0400)
* 'release' of git://github.com/melinath/philo:
  Minor correction to django-mptt requirements.
  Upped version information to 0.1rc. Switched from distutils to setuptools and added dependency information and metadata.
  Added documentation for has_navigation and navigation_host filters. Added examples of Node.navigation use to Navigation docs. Added more human-friendly general docs for shipherd.

docs/contrib/shipherd.rst
philo/__init__.py
philo/contrib/shipherd/models.py
philo/contrib/shipherd/templatetags/shipherd.py
setup.py

index 0f3b59d..915dac8 100644 (file)
@@ -3,6 +3,26 @@ Shipherd
 
 .. automodule:: philo.contrib.shipherd
        :members:
+       
+       :class:`.Node`\ s are useful for structuring a website; however, they are inherently unsuitable for creating site navigation.
+       
+       The most glaring problem is that a navigation tree based on :class:`.Node`\ s would have one :class:`.Node` as the root, whereas navigation usually has multiple objects at the top level.
+       
+       Additionally, navigation needs to have display text that is relevant to the current context; however, :class:`.Node`\ s do not have a field for that, and :class:`.View` subclasses with a name or title field will generally need to use it for database-searchable names.
+       
+       Finally, :class:`.Node` structures are inherently unordered, while navigation is inherently ordered.
+       
+       :mod:`~philo.contrib.shipherd` exists to resolve these issues by separating navigation structures from :class:`.Node` structures. It is instead structured around the way that site navigation works in the wild:
+       
+       * A site may have one or more independent navigation bars (Main navigation, side navigation, etc.)
+       * A navigation bar may be shared by sections of the website, or even by the entire site.
+       * A navigation bar has a certain depth that it displays to.
+       
+       The :class:`.Navigation` model supplies these features by attaching itself to a :class:`.Node` via :class:`ForeignKey` and adding a :attr:`navigation` property to :class:`.Node` which provides access to a :class:`.Node` instance's inherited :class:`.Navigation`\ s.
+       
+       Each entry in the navigation bar is then represented by a :class:`.NavigationItem`, which stores information such as the :attr:`~.NavigationItem.order` and :attr:`~.NavigationItem.text` for the entry. Given an :class:`HttpRequest`, a :class:`.NavigationItem` can also tell whether it :meth:`~.NavigationItem.is_active` or :meth:`~.NavigationItem.has_active_descendants`.
+       
+       Since the common pattern is to recurse through a navigation tree and render each part similarly, :mod:`~philo.contrib.shipherd` also ships with the :ttag:`~philo.contrib.shipherd.templatetags.shipherd.recursenavigation` template tag.
 
 Models
 ++++++
@@ -28,3 +48,7 @@ Template tags
 .. automodule:: philo.contrib.shipherd.templatetags.shipherd
 
 .. autotemplatetag:: recursenavigation
+
+.. autotemplatefilter:: has_navigation
+
+.. autotemplatefilter:: navigation_host
index 32297e0..e574b70 100644 (file)
@@ -1 +1 @@
-VERSION = (0, 0)
+VERSION = (0, '1rc')
index f35be3c..a520fbe 100644 (file)
@@ -179,6 +179,15 @@ class Navigation(Entity):
        """
        :class:`Navigation` represents a group of :class:`NavigationItem`\ s that have an intrinsic relationship in terms of navigating a website. For example, a ``main`` navigation versus a ``side`` navigation, or a ``authenticated`` navigation versus an ``anonymous`` navigation.
        
+       A :class:`Navigation`'s :class:`NavigationItem`\ s will be accessible from its related :class:`.Node` and that :class:`.Node`'s descendants through a :class:`NavigationMapper` instance at :attr:`Node.navigation`. Example::
+       
+               >>> node.navigation_set.all()
+               []
+               >>> parent = node.parent
+               >>> items = parent.navigation_set.get(key='main').roots.all()
+               >>> parent.navigation["main"] == node.navigation["main"] == list(items)
+               True
+       
        """
        #: A :class:`NavigationManager` instance.
        objects = NavigationManager()
index 508eace..9e572aa 100644 (file)
@@ -155,6 +155,7 @@ def recursenavigation(parser, token):
 
 @register.filter
 def has_navigation(node, key=None):
+       """Returns ``True`` if the node has a :class:`.Navigation` with the given key and ``False`` otherwise. If ``key`` is ``None``, returns whether the node has any :class:`.Navigation`\ s at all."""
        try:
                nav = node.navigation
                if key is not None:
@@ -169,6 +170,7 @@ def has_navigation(node, key=None):
 
 @register.filter
 def navigation_host(node, key):
+       """Returns the :class:`.Node` which hosts the :class:`.Navigation` which ``node`` has inherited for ``key``. Returns ``node`` if any exceptions are encountered."""
        try:
                return Navigation.objects.filter(node__in=node.get_ancestors(include_self=True), key=key).order_by('-node__level')[0].node
        except:
index 3c18b16..6dca288 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-from distutils.core import setup
+from setuptools import setup
 import os
 
 
@@ -40,8 +40,43 @@ for dirpath, dirnames, filenames in os.walk(philo_dir):
 version = __import__('philo').VERSION
 
 setup(
-       name = 'Philo',
-       version = '%s.%s' % (version[0], version[1]),
+       name = 'philo',
+       version = '.'.join([str(v) for v in version]),
+       url = "https://github.com/ithinksw/philo",
+       description = "A foundation for developing web content management systems.",
+       long_description = open(os.path.join(root_dir, 'README.markdown')).read(),
+       maintainer = "Joseph Spiros",
+       maintainer_email = "joseph.spiros@ithinksw.com",
        packages = packages,
        data_files = data_files,
+       
+       classifiers = [
+               'Environment :: Web Environment',
+               'Framework :: Django',
+               'Intended Audience :: Developers',
+               'License :: OSI Approved :: ISC License (ISCL)',
+               'Operating System :: OS Independent',
+               'Programming Language :: Python',
+               'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+               'Topic :: Software Development :: Libraries :: Application Frameworks',
+       ],
+       platforms = ['OS Independent'],
+       license = 'ISC License (ISCL)',
+       
+       install_requires = [
+               'django>=1.3',
+               'python>=2.5.4',
+               'django-mptt>0.4.2,==dev',
+       ],
+       extras_require = {
+               'docs': ["sphinx>=1.0"],
+               'grappelli': ['django-grappelli>=2.3'],
+               'migrations': ['south>=0.7.2'],
+               'waldo-recaptcha': ['recaptcha-django'],
+               'sobol-eventlet': ['eventlet'],
+               'sobol-scrape': ['BeautifulSoup'],
+       },
+       dependency_links = [
+               'https://github.com/django-mptt/django-mptt/tarball/master#egg=django-mptt-dev'
+       ]
 )
\ No newline at end of file