summaryrefslogtreecommitdiff
path: root/repoze/bfg/urldispatch.py
blob: 9bdb1e5fa55827ad5b514724adac63861b655ff1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
from zope.interface import implements
from zope.interface import classProvides

from routes import Mapper
from routes import request_config

from repoze.bfg.interfaces import IURLDispatchModel
from repoze.bfg.interfaces import ITraverserFactory
from repoze.bfg.interfaces import ITraverser

class RoutesModel(object):
    implements(IURLDispatchModel)
    def __init__(self, **kw):
        self.__dict__.update(kw)

class RoutesMapper(object):
    """ The RoutesMapper is a wrapper for the ``get_root`` callable
    passed in to the repoze.bfg Router at initialization time.  When
    it is instantiated, it wraps the get_root of an application in
    such a way that the `Routes
    <http://routes.groovie.org/index.html>`_ engine has the 'first
    crack' at resolving the current request URL to a repoze.bfg view.
    If the ``RoutesModelTraverser`` is configured in your
    application's configure.zcml, any view that claims it is 'for' the
    interface ``repoze.bfg.interfaces.IURLDispatchModel`` will be
    called if its *name* matches the Routes 'controller' name for the
    match.  It will be passed a context object that has attributes
    that match the Routes match arguments dictionary keys.  If no
    Routes route matches the current request, the 'fallback' get_root
    is called."""
    def __init__(self, get_root):
        self.get_root = get_root
        self.mapper = Mapper(controller_scan=None, directory=None,
                             explicit=True, always_scan=False)
        self.mapper.explicit = True
        self._regs_created = False

    def __call__(self, environ):
        if not self._regs_created:
            self.mapper.create_regs([])
            self._regs_created = True
        path = environ.get('PATH_INFO', '/')
        args = self.mapper.match(path)
        if args:
            config = request_config()
            config.mapper = self.mapper
            config.mapper_dict = args
            config.host = environ.get('HTTP_HOST', environ['SERVER_NAME'])
            config.protocol = environ['wsgi.url_scheme']
            config.redirect = None
            model = RoutesModel(**args)
            return model
        # fall back to original get_root
        return self.get_root(environ)

    def connect(self, *arg, **kw):
        """ Add a route to the Routes mapper associated with this
        request. This method accepts the same arguments as a Routes
        *Mapper* object"""
        self.mapper.connect(*arg, **kw)

class RoutesModelTraverser(object):
    classProvides(ITraverserFactory)
    implements(ITraverser)
    def __init__(self, model, request):
        self.model = model
        self.request = request

    def __call__(self, environ):
        return self.model, self.model.controller, ''