Last active
October 28, 2015 15:26
-
-
Save amcgregor/1155131 to your computer and use it in GitHub Desktop.
Example router implementation and example for WebCore 2.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# encoding: utf-8 | |
import re | |
from functools import wraps | |
from collections import namedtuple | |
re_type = type(re.compile("")) | |
def route(router, route): | |
def inner(func): | |
router.register(route, func) | |
return func | |
return inner | |
class Router(object): | |
def __init__(self): | |
self.routes = list() | |
def register(self, route, obj, ctx=None, name=None): | |
parsed = self.parse(route) | |
print "registering", route, parsed | |
routes = self.routes | |
for element in parsed: | |
for i, (route, children) in enumerate(routes): | |
if route is not element: | |
continue | |
if not isinstance(children, list): | |
children = [(None, children)] | |
routes[i] = (route, children) | |
routes = children | |
break | |
else: | |
routes.append((element, obj)) | |
def parse(self, route): | |
parts = route.lstrip('/').split('/') | |
for i, part in enumerate(parts): | |
if '{' not in part: | |
continue | |
elif '}' not in part: | |
raise ValueError("Route match must not contain forward slashes.") | |
sub = list() | |
while part: | |
prefix, _, match = part.partition('{') | |
name, _, part = match.partition('}') | |
sub.append(prefix) | |
name, _, regex = name.partition(':') | |
sub.append('(?P<%s>%s)' % (name, regex or r'[^/]+')) | |
parts[i] = re.compile(''.join(sub)) | |
return parts | |
def route(self, path): | |
routes = self.routes | |
path = path.lstrip('/').split('/') + [None] | |
match = dict() | |
for i, element in enumerate(path): | |
for route, children in routes: | |
if isinstance(route, re_type): | |
matched = route.match(element) | |
if not matched: continue | |
match.update(matched.groupdict()) | |
elif route != element: | |
continue | |
if not isinstance(children, list): | |
return children, [i for i in path[i+1:] if i is not None], match | |
routes = children | |
break | |
else: | |
raise ValueError("Could not find route to satisfy path.") | |
raise ValueError("Could not find route to satisfy path.") | |
router = Router() | |
@route(router, '/') | |
def index(ctx): | |
print "index" | |
@route(router, '/create') | |
def create(ctx): | |
pass | |
@route(router, '/{id}') | |
def show(ctx, id): | |
pass | |
@route(router, '/{id}/modify') | |
def modify(ctx, id): | |
pass | |
@route(router, '/{id}/delete') | |
def delete(ctx, id): | |
pass | |
__import__('pprint').pprint(router.routes) | |
for i in ('/', '/create', '/27', '/42/modify', '/64/delete', '/64/delete/confirm', '/create/diz'): | |
print i, '\t\t' if len(i) < 7 else '\t', router.route(i) | |
# Results: | |
""" | |
registering / [''] | |
registering /create ['create'] | |
registering /{id} [<_sre.SRE_Pattern object at 0x109152e90>] | |
registering /{id}/modify [<_sre.SRE_Pattern object at 0x109152e90>, 'modify'] | |
registering /{id}/delete [<_sre.SRE_Pattern object at 0x109152e90>, 'delete'] | |
[('', <function index at 0x1091c3a28>), | |
('create', <function create at 0x1091c3aa0>), | |
(<_sre.SRE_Pattern object at 0x109152e90>, | |
[(None, <function show at 0x1091c3b18>), | |
('modify', <function modify at 0x1091c3b90>), | |
('delete', <function delete at 0x1091c3c08>)])] | |
/ (<function index at 0x1091c3a28>, [], {}) | |
/create (<function create at 0x1091c3aa0>, [], {}) | |
/27 (<function show at 0x1091c3b18>, [], {'id': '27'}) | |
/42/modify (<function modify at 0x1091c3b90>, [], {'id': '42'}) | |
/64/delete (<function delete at 0x1091c3c08>, [], {'id': '64'}) | |
/64/delete/confirm (<function delete at 0x1091c3c08>, ['confirm'], {'id': '64'}) | |
/create/diz (<function create at 0x1091c3aa0>, ['diz'], {}) | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment