From 05c02322f5a09c14f49c529d6fd885153e52c66f Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 24 Jun 2009 19:23:43 +0000 Subject: Merge noroutes branch to trunk. --- repoze/bfg/urldispatch.py | 129 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 89 insertions(+), 40 deletions(-) (limited to 'repoze/bfg/urldispatch.py') diff --git a/repoze/bfg/urldispatch.py b/repoze/bfg/urldispatch.py index 0281b52b3..497d3980e 100644 --- a/repoze/bfg/urldispatch.py +++ b/repoze/bfg/urldispatch.py @@ -1,53 +1,102 @@ -from routes import Mapper -from routes import request_config +import re _marker = object() -class RoutesRootFactory(Mapper): - def __init__(self, default_root_factory, **kw): +class Route(object): + def __init__(self, name, matcher, generator, factory): + self.name = name + self.matcher = matcher + self.generator = generator + self.factory = factory + + def match(self, path): + return self.matcher(path) + + def generate(self, kw): + return self.generator(kw) + +class RoutesRootFactory(object): + def __init__(self, default_root_factory): self.default_root_factory = default_root_factory - kw['controller_scan'] = None - kw['always_scan'] = False - kw['directory'] = None - kw['explicit'] = True - Mapper.__init__(self, **kw) - self._regs_created = False + self.routelist = [] + self.routes = {} def has_routes(self): - return bool(self.matchlist) + return bool(self.routelist) - def connect(self, *arg, **kw): - result = Mapper.connect(self, *arg, **kw) - route = self.matchlist[-1] - route._factory = None # overridden by ZCML - return result + def connect(self, name, path, factory=None): + matcher, generator = _compile_route(path) + route = Route(name, matcher, generator, factory) + self.routelist.append(route) + self.routes[name] = route + return route + + def generate(self, name, kw): + return self.routes[name].generate(kw) def __call__(self, environ): - if not self._regs_created: - self.create_regs([]) - self._regs_created = True path = environ.get('PATH_INFO', '/') - self.environ = environ # sets the thread local - match = self.routematch(path) - if match: - args, route = match - else: - args = None - if isinstance(args, dict): # might be an empty dict - args = args.copy() - config = request_config() - config.mapper = self - config.mapper_dict = args - config.host = environ.get('HTTP_HOST', environ['SERVER_NAME']) - config.protocol = environ['wsgi.url_scheme'] - config.redirect = None - environ['wsgiorg.routing_args'] = ((), args) - environ['bfg.routes.route'] = route - environ['bfg.routes.matchdict'] = args - adhoc_attrs = environ.setdefault('webob.adhoc_attrs', {}) - adhoc_attrs['matchdict'] = args - factory = route._factory or self.default_root_factory - return factory(environ) + for route in self.routelist: + match = route.match(path) + if match is not None: + environ['wsgiorg.routing_args'] = ((), match) + environ['bfg.routes.route'] = route + environ['bfg.routes.matchdict'] = match + adhoc_attrs = environ.setdefault('webob.adhoc_attrs', {}) + adhoc_attrs['matchdict'] = match + factory = route.factory or self.default_root_factory + return factory(environ) return self.default_root_factory(environ) +# stolen from bobo and modified +route_re = re.compile(r'(/:[a-zA-Z]\w*)') +def _compile_route(route): + if not route.startswith('/'): + route = '/' + route + star = None + if '*' in route: + route, star = route.rsplit('*', 1) + pat = route_re.split(route) + pat.reverse() + rpat = [] + gen = [] + prefix = pat.pop() + if prefix: + rpat.append(re.escape(prefix)) + gen.append(prefix) + while pat: + name = pat.pop() + name = name[2:] + gen.append('/%%(%s)s' % name) + name = '/(?P<%s>[^/]*)' % name + rpat.append(name) + s = pat.pop() + if s: + rpat.append(re.escape(s)) + gen.append(s) + + if star: + rpat.append('(?P<%s>.*?)' % star) + gen.append('%%(%s)s' % star) + + pattern = ''.join(rpat) + '$' + + match = re.compile(pattern).match + def matcher(path): + m = match(path) + if m is None: + return m + return dict(item for item in m.groupdict().iteritems() + if item[1] is not None) + + gen = ''.join(gen) + def generator(dict): + newdict = {} + for k, v in dict.items(): + if isinstance(v, unicode): + v = v.encode('utf-8') + newdict[k] = v + return gen % newdict + + return matcher, generator -- cgit v1.2.3