comparison piecrust/routing.py @ 173:0a86a7a6b284

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.
author Ludovic Chabant <ludovic@chabant.com>
date Sat, 03 Jan 2015 21:10:44 -0800
parents a42469dbdc47
children d47d9493bb0a
comparison
equal deleted inserted replaced
172:4fc1d306046b 173:0a86a7a6b284
24 self.app = app 24 self.app = app
25 uri = cfg['url'] 25 uri = cfg['url']
26 self.uri_root = app.config.get('site/root').rstrip('/') + '/' 26 self.uri_root = app.config.get('site/root').rstrip('/') + '/'
27 self.uri_pattern = uri.lstrip('/') 27 self.uri_pattern = uri.lstrip('/')
28 self.uri_format = route_re.sub(self._uriFormatRepl, self.uri_pattern) 28 self.uri_format = route_re.sub(self._uriFormatRepl, self.uri_pattern)
29
30 # Get the straight-forward regex for matching this URI pattern.
29 p = route_re.sub(self._uriPatternRepl, self.uri_pattern) + '$' 31 p = route_re.sub(self._uriPatternRepl, self.uri_pattern) + '$'
30 self.uri_re = re.compile(p) 32 self.uri_re = re.compile(p)
33
34 # If the URI pattern has a 'path'-type component, we'll need to match
35 # the versions for which that component is empty. So for instance if
36 # we have `/foo/%path:bar%`, we may need to match `/foo` (note the
37 # lack of a trailing slash). We have to build a special pattern (in
38 # this case without that trailing slash) to match those situations.
39 # (maybe there's a better way to do it but I can't think of any
40 # right now)
41 uri_pattern_no_path = (
42 route_re.sub(self._uriNoPathRepl, self.uri_pattern)
43 .replace('//', '/')
44 .rstrip('/'))
45 if uri_pattern_no_path != self.uri_pattern:
46 p = route_re.sub(self._uriPatternRepl, uri_pattern_no_path) + '$'
47 self.uri_re_no_path = re.compile(p)
48 else:
49 self.uri_re_no_path = None
50
31 self.source_name = cfg['source'] 51 self.source_name = cfg['source']
32 self.taxonomy = cfg.get('taxonomy') 52 self.taxonomy = cfg.get('taxonomy')
33 self.required_source_metadata = [] 53 self.required_source_metadata = set()
34 for m in route_re.finditer(uri): 54 for m in route_re.finditer(uri):
35 self.required_source_metadata.append(m.group('name')) 55 self.required_source_metadata.add(m.group('name'))
36 self.template_func = None 56 self.template_func = None
37 self.template_func_name = None 57 self.template_func_name = None
38 self.template_func_args = [] 58 self.template_func_args = []
39 self._createTemplateFunc(cfg.get('func')) 59 self._createTemplateFunc(cfg.get('func'))
40 60
48 68
49 @property 69 @property
50 def source_realm(self): 70 def source_realm(self):
51 return self.source.realm 71 return self.source.realm
52 72
53 def isMatch(self, source_metadata): 73 def matchesMetadata(self, source_metadata):
54 return True 74 return self.required_source_metadata.issubset(source_metadata.keys())
75
76 def matchUri(self, uri):
77 m = self.uri_re.match(uri)
78 if m:
79 return m
80 if self.uri_re_no_path:
81 m = self.uri_re_no_path.match(uri)
82 if m:
83 return m
84 return None
55 85
56 def getUri(self, source_metadata, provider=None): 86 def getUri(self, source_metadata, provider=None):
57 if provider: 87 if provider:
58 source_metadata = dict(source_metadata) 88 source_metadata = dict(source_metadata)
59 source_metadata.update(provider.getRouteMetadata()) 89 source_metadata.update(provider.getRouteMetadata())
76 106
77 def _uriPatternRepl(self, m): 107 def _uriPatternRepl(self, m):
78 name = m.group('name') 108 name = m.group('name')
79 qualifier = m.group('qual') 109 qualifier = m.group('qual')
80 if qualifier == 'path': 110 if qualifier == 'path':
81 return r'(?P<%s>.*)' % name 111 return r'(?P<%s>[^\?]*)' % name
112 return r'(?P<%s>[^/\?]+)' % name
113
114 def _uriNoPathRepl(self, m):
115 name = m.group('name')
116 qualifier = m.group('qual')
117 if qualifier == 'path':
118 return ''
82 return r'(?P<%s>[^/\?]+)' % name 119 return r'(?P<%s>[^/\?]+)' % name
83 120
84 def _createTemplateFunc(self, func_def): 121 def _createTemplateFunc(self, func_def):
85 if func_def is None: 122 if func_def is None:
86 return 123 return