
Mappings
********

WFront is driven by a routing map or *mapping*.  The mapping is a
sequence of 1 or more 3-tuples:

   (**path specification**, **wsgi callable**, **filter**)

For example:

   mapping = [
       ('www.example.com', app1, None),
       ('www.example.com:3000', app2, {'environ_key':'value'})
   ]


Path Specifications
===================

Path specifications (or path specs) are compared to the WSGI environ's
requested **hostname**, **port** and **path**.  A path spec is a
colon-separated string, and sections may use ``*`` wildcard matching.
Empty or missing sections match anything.

   www.example.com
   www.example.com:80
   www.example.com:80:/some/path
   *.example.com::/some/path
   :80
   ::/some/path

The incoming ``Host:`` header and ``environ['PATH_INFO']`` supply the
match data by default.


WSGI Callables
==============

The WSGI application may be supplied either as a callable or a string.

Strings are evaluated and are expected to resolve to a callable.  The
evaluation syntax is similar to that of several popular Python string
resolvers.

**Dotted Path**

Format:
   ``wsgiref.simple_server.demo_app``

Imports modules as needed, doing a getattr() on each to reach a
target.  The above is identical to:

   import wsgiref.simple_server
   wsgiref.simple_server.demo_app

**Import and Eval**

Format:
   ``os:environ["PATH"]``

Imports the dotted module path before the colon, and evals() the
portion after the colon in that module's namespace.  The above is
identical to:

   import os
   os.environ["PATH"]


Filters
=======

Filters have the opportunity to fine-tune the ``environ`` before the
WSGI callable executes and/or rewrite the WSGI response.  Filters may
take several forms.

``None``

   No filtering takes place.

A ``dict``

   WFront will ``environ.update(your_dict)`` before invoking the WSGI
   callable.

A ``dict`` with rewriting directives

   You may request simple environ transformations, for example
   removing a prefix from ``SCRIPT_NAME``, trimming off part
   ``PATH_INFO``, adding to existing values, etc.  See *Built-In
   Cleanup Filter*.  The rewriting functionality is also available as
   an independent WSGI middleware.

A callable

   The most general option is a callable that wraps the WSGI
   application, of the form:

   filter(app, environ, start_response) -> response

   The filter is responsible for producing the WSGI response, usually
   through ``return app(environ, start_response)``.  Like the WSGI
   application callable, a filter callable may also be supplied as a
   string to be resolved at runtime.


Mapping Helpers
===============

Some mappings can be made briefer and more idiomatic with one of the
built-in mapping helpers.  These are simple extensions of ``list``
that build mapping 3-tuples in different ways.


MacroMap
--------

class wfront.MacroMap(sequence=None, macros={})

   Bases: ``list``

   Expands simple macros in routing specs.

   MacroMap is constructed with a simple mapping of short-name to
   long-name, expanding any references of the form ``{short-name}`` to
   ``long-name``:

      >>> from wfront import MacroMap
      >>> mm = MacroMap(macros={'domain': 'example.com'})
      >>> mm.add('{domain}:http', app)
      >>> mm.add('www.{domain}:http', app)

   Or in bulk:

   >>> expansions = {'domain': 'example.com'}
   >>> routes = [('{domain}', app), ('www.{domain}', app)]
   >>> mapping = MacroMap(routes, macros=expansions)
   >>> mapping
   [('example.com', app, None), ('www.example.com', app, None)]

   The non-standard syntax ``{}`` was chosen to avoid conflicts with
   definitions loaded from ConfigParser ``.ini`` files.

   add(spec, app, filter=None)

      Append a route from *spec* to *app*.

      Parameters:
         * *spec* -- a routing specification.  May contain macro
           substitution tokens of the form ``{token}``.  Unmatched
           tokens will raise an error.

         * *app* -- a WSGI callable or string reference

         * *filter* -- optional, a mapping filter


PathMap
-------

class wfront.PathMap(sequence=None)

   Bases: ``list``

   A route mapping helper that sets up simple path-based routing.

   Routes are created with wildcarded host and port by default.
   Useful for simple path forwarders:

      >>> from wfront import PathMap
      >>> pm = PathMap()
      >>> pm.add('/foo', app1)
      >>> pm.add('/', app2)

   Mappings can also be made by the constructor:

      >>> mapping = PathMap([('/foo', app1), ('/', app2)])
      >>> mapping
      [('*:*:/foo', app1, None), ('*:*:/', app2, None)]

   PathMap is syntactic sugar for normal 3-tuple mappings.  All
   features available to regular mappings are available to PathMap.

   __init__(sequence=None)

      Construct a PathMap.

      Parameter:
         *sequence* -- Optional sequence of n-tuples.  Each will be
         supplied positionally to ``add()``.  Each n-tuple must
         contain at least 2 members (``(path, app)``).

   add(path, app, filter=None, host='*', port='*')

      Append a route from *path* to *app*.

      Parameters:
         * *path* -- a URL path to match

         * *app* -- a WSGI callable or string reference

         * *filter* -- optional, a mapping filter

         * *host* -- the host portion to match, by default ``*``

         * *port* -- the port portion to match, by default ``*``
