# HG changeset patch # User Ludovic Chabant # Date 1420348244 28800 # Node ID 0a86a7a6b284575c3e80305ee865597a67657a00 # Parent 4fc1d306046b58063a9c597579c8858274da176d routes: Actually match metadata when finding routes, fix problems with paths. When we look for a route that matches a given page, we now look at the source metadata that comes with that page, and compare it to the metadata we need to build URIs. Also, when matching URIs, we handle the case where a 'path'-component in our pattern may be completely empty, and thus we may be missing some trailing slashes in the URI. diff -r 4fc1d306046b -r 0a86a7a6b284 piecrust/app.py --- a/piecrust/app.py Sat Jan 03 20:52:19 2015 -0800 +++ b/piecrust/app.py Sat Jan 03 21:10:44 2015 -0800 @@ -512,7 +512,7 @@ def getRoute(self, source_name, source_metadata): for route in self.getRoutes(source_name, True): - if route.isMatch(source_metadata): + if route.matchesMetadata(source_metadata): return route return None diff -r 4fc1d306046b -r 0a86a7a6b284 piecrust/routing.py --- a/piecrust/routing.py Sat Jan 03 20:52:19 2015 -0800 +++ b/piecrust/routing.py Sat Jan 03 21:10:44 2015 -0800 @@ -26,13 +26,33 @@ self.uri_root = app.config.get('site/root').rstrip('/') + '/' self.uri_pattern = uri.lstrip('/') self.uri_format = route_re.sub(self._uriFormatRepl, self.uri_pattern) + + # Get the straight-forward regex for matching this URI pattern. p = route_re.sub(self._uriPatternRepl, self.uri_pattern) + '$' self.uri_re = re.compile(p) + + # If the URI pattern has a 'path'-type component, we'll need to match + # the versions for which that component is empty. So for instance if + # we have `/foo/%path:bar%`, we may need to match `/foo` (note the + # lack of a trailing slash). We have to build a special pattern (in + # this case without that trailing slash) to match those situations. + # (maybe there's a better way to do it but I can't think of any + # right now) + uri_pattern_no_path = ( + route_re.sub(self._uriNoPathRepl, self.uri_pattern) + .replace('//', '/') + .rstrip('/')) + if uri_pattern_no_path != self.uri_pattern: + p = route_re.sub(self._uriPatternRepl, uri_pattern_no_path) + '$' + self.uri_re_no_path = re.compile(p) + else: + self.uri_re_no_path = None + self.source_name = cfg['source'] self.taxonomy = cfg.get('taxonomy') - self.required_source_metadata = [] + self.required_source_metadata = set() for m in route_re.finditer(uri): - self.required_source_metadata.append(m.group('name')) + self.required_source_metadata.add(m.group('name')) self.template_func = None self.template_func_name = None self.template_func_args = [] @@ -50,8 +70,18 @@ def source_realm(self): return self.source.realm - def isMatch(self, source_metadata): - return True + def matchesMetadata(self, source_metadata): + return self.required_source_metadata.issubset(source_metadata.keys()) + + def matchUri(self, uri): + m = self.uri_re.match(uri) + if m: + return m + if self.uri_re_no_path: + m = self.uri_re_no_path.match(uri) + if m: + return m + return None def getUri(self, source_metadata, provider=None): if provider: @@ -78,7 +108,14 @@ name = m.group('name') qualifier = m.group('qual') if qualifier == 'path': - return r'(?P<%s>.*)' % name + return r'(?P<%s>[^\?]*)' % name + return r'(?P<%s>[^/\?]+)' % name + + def _uriNoPathRepl(self, m): + name = m.group('name') + qualifier = m.group('qual') + if qualifier == 'path': + return '' return r'(?P<%s>[^/\?]+)' % name def _createTemplateFunc(self, func_def): diff -r 4fc1d306046b -r 0a86a7a6b284 piecrust/serving.py --- a/piecrust/serving.py Sat Jan 03 20:52:19 2015 -0800 +++ b/piecrust/serving.py Sat Jan 03 21:10:44 2015 -0800 @@ -415,7 +415,7 @@ uri = uri.lstrip('/') res = [] for route in routes: - m = route.uri_re.match(uri) + m = route.matchUri(uri) if m: metadata = m.groupdict() res.append((route, metadata))