diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-01-18 23:38:47 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-01-18 23:38:47 +0000 |
| commit | 62267e01d6eeaf8de871487898ad1ce02878c29a (patch) | |
| tree | 234346245e58993c27e139906ee7a19a7b67a8e4 /docs | |
| parent | 58afb33d70dece410b998a9c064eba42e3f843d7 (diff) | |
| download | pyramid-62267e01d6eeaf8de871487898ad1ce02878c29a.tar.gz pyramid-62267e01d6eeaf8de871487898ad1ce02878c29a.tar.bz2 pyramid-62267e01d6eeaf8de871487898ad1ce02878c29a.zip | |
Merge "routesmapper branch" to trunk.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/api/view.rst | 3 | ||||
| -rw-r--r-- | docs/narr/urldispatch.rst | 242 |
2 files changed, 97 insertions, 148 deletions
diff --git a/docs/api/view.rst b/docs/api/view.rst index 5afd1118a..3b34b7e22 100644 --- a/docs/api/view.rst +++ b/docs/api/view.rst @@ -15,7 +15,8 @@ .. autofunction:: view_execution_permitted - .. autofunction:: bfg_view + .. autoclass:: bfg_view + :members: .. autoclass:: static :members: diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index 7df7ce8ed..e6e5287c1 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -14,17 +14,10 @@ is a mechanism which allows you to declaratively map URLs to code. to is defined by a *controller* and an *action*. However, neither concept (controller nor action) exists within :mod:`repoze.bfg`. Instead, when you map a URL pattern to - code in bfg, you will map the URL patterm to a :term:`view`. - As a result, there is a bit of mental gynmastics you'll need - to do when dealing with Routes URL dispatch in bfg. In - general, whenever you see the name *controller* in the - context of :term:`Routes`, you should map that mentally to - the bfg term :term:`view`. *Actions* do not exist in - :mod:`repoze.bfg`: in other frameworks these may refer to - methods of a *controller class*, but since views in - :mod:`repoze.bfg` are simple callables (usually functions) - as opposed to classes, there is no direct concept mapping of - an action. + code in bfg, you will map the URL patterm to a + :term:`context` and a :term:`view name`. Once the context + is found, "normal" :mod:`repoze.bfg` :term:`view` lookup + will be done using the context and the view name. It often makes a lot of sense to use :term:`URL dispatch` instead of :term:`traversal` in an application that has no natural hierarchy. @@ -42,96 +35,90 @@ natural :term:`traversal`, allowing a :term:`Routes` "mapper" object to have the "first crack" at resolving a given URL, allowing the framework to fall back to traversal as necessary. -To this end, the :mod:`repoze.bfg` framework defines a module named -:mod:`repoze.bfg.urldispatch`. This module contains a class named -:class:`RoutesMapper`. An Instance of this class is willing to act as -a :mod:`repoze.bfg` ``get_root`` callable, and is willing to be -configured with *route mappings* as necessary via its ``.connect`` -method. - -The :class:`RoutesMapper` is essentially willing to act as the "root -callable". When it acts as such a callable, it is willing to check -the requested URL against a *routes map*, and subsequently look up and -call a :mod:`repoze.bfg` view with the information it finds within a +To this end, the :mod:`repoze.bfg` framework allows you to inject +``route` ZCML directives into your application's ``configure.zcml`` +file. These directives have much the same job as imperatively using +the ``.connect`` method of a routes Mapper object, with some +BFG-specific behavior. + +When any ``route`` ZCML directive is used, BFG wraps the "default" +"root factory" (aka ``get_root``) in a special ``RoutesRootFactory`` +instance. This then acts as the root factory (a callable). When it +acts as such a callable, it is willing to check the requested URL +against a *routes map* to find the :term:`context` and the +:term:`view name`. Subsequently, BFG will look up and call a +:mod:`repoze.bfg` view with the information it finds within a particular route, if any configured route matches the currently -requested URL. A ``get_root`` callable is a callable passed to the -:mod:`repoze.bfg` framework by an application, allowing -:mod:`repoze.bfg` to fail over to another "root" object in case the -routes mapper can't find a match for a particular URL. If no URL -matches, the :class:`RoutesMapper` will fall back to calling the -fallback ``get_root`` callable that is passed in to it at construction -time, which allows your application to fall back to a different "root" -(perhaps one based on traversal). By configuring a -:class:`RoutesMapper` appropriately, you can mix and match URL -dispatch and traversal in this way. +requested URL. If no route matches the configured routes, +:mod:`repoze.bfg` will fail over to calling the ``get_root`` callable +passed to the application in it's ``make_app`` function. By +configuring your ZCML ``route`` statements appropriately, you can mix +and match URL dispatch and traversal in this way. .. note:: See :ref:`modelspy_project_section` for an example of a - simple ``get_root`` callable that uses traversal. + simple ``get_root`` callable that will use traversal. -Configuring a :class:`RoutesMapper` with individual routes is -performed by creating an instance of a :class:`RoutesMapper`, and -calling its ``.connect`` method with the same arguments you'd use if -you were creating a route mapping using a "raw" :term:`Routes` -``Mapper`` object. See `Setting up routes +Each ZCML ``route``statement equals a call to the term:`Routes` +``Mapper`` object's ``connect`` method. See `Setting up routes <http://routes.groovie.org/manual.html#setting-up-routes>`_ for -examples of using a Routes ``Mapper`` object. When you are finished -configuring it, you can pass it as a ``get_root`` callable to +examples of using a Routes ``Mapper`` object outside of :mod:`repoze.bfg`. -When you configure a :class:`RoutesMapper` with a route via -``.connect``, you'll pass in the name of a ``controller`` as a keyword -argument. This will be a string. The string should match the -**name** of a :mod:`repoze.bfg` :term:`view` callable that is -registered for the type ``repoze.bfg.interfaces.IRoutesContext`` (via -a ZCML directive, see :ref:`views_chapter` for more information about -registering bfg views). When a URL is matched, this view will be -called with a :term:`context` manufactured "on the fly" by the -:class:`RoutesMapper`. The context object will have attributes which -match all of the :term:`Routes` matching arguments returned by the -mapper. - Example 1 --------- -Below is an example of configuring a :class:`RoutesMapper` for usage -as a ``get_root`` callback. +Below is an example of some route statements you might add to your +``configure.zcml``: -.. code-block:: python +.. code-block:: xml :linenos: - from repoze.bfg.urldispatch import RoutesMapper + <route + path="ideas/:idea" + view_name="ideas"/> - def fallback_get_root(environ): - return {} + <route + path="users/:user" + view_name="users"/> - root = RoutesMapper(fallback_get_root) - root.connect('ideas/:idea', controller='ideas') - root.connect('users/:user', controller='users') - root.connect('tags/:tag', controller='tags') + <route + path="tags/:tag" + view_name="tags"/> -The above configuration will allow the mapper to service URLs in the forms:: +The above configuration will allow :mod:`repoze.bfg` to service URLs +in these forms: + +.. code-block:: bash + :linenos: /ideas/<ideaname> /users/<username> /tags/<tagname> -If this mapper is used as a ``get_root`` callback, when a URL matches -the pattern ``/ideas/<ideaname>``, the view registered with the name -'ideas' for the interface ``repoze.bfg.interfaces.IRoutesContext`` -will be called. An error will be raised if no view can be found with -that interfaces type or name. +When a URL matches the pattern ``/ideas/<ideaname>``, the view +registered with the name 'ideas' for the interface +``repoze.bfg.interfaces.IRoutesContext`` will be called. An error +will be raised if no view can be found with that interfaces type or +name. The context object passed to a view found as the result of URL dispatch will be an instance of the ``repoze.bfg.urldispatch.RoutesContext`` object. You can override -this behavior by passing in a ``context_factory`` argument to the -mapper's connect method for a particular route. The -``context_factory`` should be a callable that accepts arbitrary -keyword arguments and returns an instance of a class that will be the -context used by the view. - -If no route matches in the above configuration, the routes mapper will -call the "fallback" ``get_root`` callable provided to it above. +this behavior by passing in a ``context_factory`` argument to the ZCML +directive for a particular route. The ``context_factory`` should be a +callable that accepts arbitrary keyword arguments and returns an +instance of a class that will be the context used by the view. + +The context object will be decorated by default with the +``repoze.bfg.interfaces.IRoutesContext`` interface. To decorate a +context found via a route with other interfaces, you can use a +``context_interfaces`` attribute on the ZCML statement. It should be +a space-separated list of dotted Python names that point at interfaces. + +If no route matches in the above configuration, :mod:`repoze.bfg` will +call the "fallback" ``get_root`` callable provided to it during +``make_app`. If the "fallback" ``get_root`` is None, a ``NotFound`` +error will be raised when no route matches. Example 2 --------- @@ -144,35 +131,31 @@ function is as follows: :linenos: <view - for="repoze.bfg.interfaces.IRoutesContext" + for=".interfaces.ISomeContext" view=".views.articles_view" name="articles" /> + <route + path="archives/:article" + view_name="articles" + context_factory=".models.Article" + context_interfaces=".interfaces.ISomeContext" + /> + All context objects found via Routes URL dispatch will provide the -``IRoutesContext`` interface (attached dynamically). You might then -configure the ``RoutesMapper`` like so: +``IRoutesContext`` interface (attached dynamically). The above +``route`` statement will also cause contexts generated by the route to +have the ``.interfaces.ISomeContext`` interface as well. The +``.models`` modulemight look like so: .. code-block:: python :linenos: - from repoze.bfg.router import make_app - from repoze.bfg.urldispatch import RoutesMapper - - def fallback_get_root(environ): - return {} # the graph traversal root is empty in this example - class Article(object): def __init__(self, **kw): self.__dict__.update(kw) - get_root = RoutesMapper(fallback_get_root) - get_root.connect('archives/:article', controller='articles', - context_factory=Article) - - import myapp - app = make_app(get_root, myapp) - The effect of this configuration: when this :mod:`repoze.bfg` application runs, if any URL matches the pattern ``archives/:article``, the ``.views.articles_view`` view will be @@ -195,65 +178,33 @@ called. This framework operates in terms of ACLs (Access Control Lists, see :ref:`security_chapter` for more information about the :mod:`repoze.bfg` security subsystem). A common thing to want to do is to attach an ``__acl__`` to the context object dynamically for -declarative security purposes. A Routes 'trick' can allow for this. - -Routes makes it possible to pass a ``conditions`` argument to the -``connect`` method of a mapper. The value of ``conditions`` is a -dictionary. If you pass a ``conditions`` dictionary to this -``connect`` method with a ``function`` key that has a value which is a -Python function, this function can be used to update the ``__acl__`` -of the model object. - -When Routes tries to resolve a particular route via a match, the route -object itself will pass the environment and the "match_dict" to the -``conditions`` function. Typically, a ``conditions`` function decides -whether or not the route match should "succeed". But we'll use it -differently: we'll use it to update the "match dict". The match dict -is what is eventually returned by Routes to :mod:`repoze.bfg`. If the -function that is used as the ``conditions`` function adds an -``__acl__`` key/value pair to the match dict and subsequently always -returns ``True`` (indicating that the "condition" passed), the -resulting ``__acl__`` key and its value will appear in the match -dictionary. Since all values returned in the match dictionary are -eventually set on your context object, :mod:`repoze.bfg` will set an -``__acl__`` attribute on the context object returned to -:mod:`repoze.bfg` matching the value you've put into the match -dictionary under ``__acl__``, just in time for the :mod:`repoze.bfg` -security machinery to find it. :mod:`repoze.bfg` security will allow -or deny further processing of the request based on the ACL. - -Here's an example: +declarative security purposes. You can use the ``context_factory`` +argument that points at a context factory which attaches a custom +``__acl__`` to an object at its creation time. -.. code-block:: python +Such a ``context_factory`` might look like so: - from repoze.bfg.router import make_app - from repoze.bfg.security import Allow - from repoze.bfg.urldispatch import RoutesMapper - - def fallback_get_root(environ): - return {} # the graph traversal root is empty in this example +.. code-block:: python + :linenos: class Article(object): def __init__(self, **kw): self.__dict__.update(kw) - def add_acl(environ, match_dict): - if match_dict.get('article') == 'article1': - routes_dict['__acl__'] = [ (Allow, 'editor', 'view') ] - - get_root = RoutesMapper(fallback_get_root) - get_root.connect('archives/:article', controller='articles', - context_factory=Article, conditions={'function':add_acl}) - - import myapp - app = make_app(get_root, myapp) - -If the route ``archives/:article`` is matched, :mod:`repoze.bfg` will -generate an ``Article`` :term:`context` with an ACL on it that allows -the ``editor`` principal the ``view`` permission. Obviously you can -do more generic things that inspect the routes match dict to see if -the ``article`` argument matches a particular string; our sample -``add_acl`` function is not very ambitious. + def article_context_factory(**kw): + model = Article(**kw) + article = kw.get('article', None) + if article == '1': + model.__acl__ = [ (Allow, 'editor', 'view') ] + return model + +If the route ``archives/:article`` is matched, and the article number +is ``1``, :mod:`repoze.bfg` will generate an ``Article`` +:term:`context` with an ACL on it that allows the ``editor`` principal +the ``view`` permission. Obviously you can do more generic things +that inspect the routes match dict to see if the ``article`` argument +matches a particular string; our sample ``article_context_factory`` +function is not very ambitious. .. note:: See :ref:`security_chapter` for more information about :mod:`repoze.bfg` security and ACLs. @@ -269,6 +220,3 @@ Further Documentation and Examples URL-dispatch related API documentation is available in :ref:`urldispatch_module` . -The `repoze.shootout <http://svn.repoze.org/repoze.shootout/trunk/>`_ -application uses URL dispatch to serve its "ideas", "users" and "tags" -pages. |
