Skip to content

Instantly share code, notes, and snippets.

@amcgregor
Last active October 28, 2015 15:26
Show Gist options
  • Save amcgregor/1155131 to your computer and use it in GitHub Desktop.
Save amcgregor/1155131 to your computer and use it in GitHub Desktop.
Example router implementation and example for WebCore 2.
# 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
print
__import__('pprint').pprint(router.routes)
print
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