Created
September 3, 2012 09:59
-
-
Save tonyseek/3608222 to your computer and use it in GitHub Desktop.
A traversal style dispatcher which is alike Quixote.
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
#!/usr/bin/env python | |
#-*- coding:utf-8 -*- | |
def dispatch(entry_object, path, spliter="/"): | |
"""Starting with an entry object and dispatching the request by url path. | |
>>> class GroupList(object): | |
... exports = frozenset(["create"]) | |
... | |
... def _q_index(self): | |
... return "groups" | |
... | |
... def _q_lookup(self, group_id): | |
... return Group(group_id) | |
... | |
... def create(self): | |
... return "apply-create" | |
>>> | |
>>> class Group(object): | |
... exports = frozenset(["members", "overview"]) | |
... | |
... def __init__(self, group_id): | |
... self.group_id = group_id | |
... | |
... def _q_index(self): | |
... return self.overview() | |
... | |
... @property | |
... def members(self): | |
... return MemberList(self.group_id) | |
... | |
... def overview(self): | |
... return "group-%s-overview" % self.group_id | |
>>> | |
>>> class MemberList(object): | |
... def __init__(self, group_id): | |
... self.group_id = group_id | |
... | |
... def _q_access(self): | |
... if not self.group_id.isdigit(): | |
... raise ValueError("WTF") | |
... | |
... def _q_index(self): | |
... return "members-of-group-%s" % self.group_id | |
... | |
>>> class MainDispatcher(object): | |
... exports = ["groups"] | |
... groups = GroupList() | |
>>> | |
>>> entry_object = MainDispatcher() | |
>>> | |
>>> dispatch(entry_object, "/") | |
Traceback (most recent call last): | |
... | |
TraversalError: Not found public attribute or dynamic finder | |
>>> | |
>>> dispatch(entry_object, "/groups")() | |
'groups' | |
>>> dispatch(entry_object, "/groups/create")() | |
'apply-create' | |
>>> dispatch(entry_object, "/groups/100001")() | |
'group-100001-overview' | |
>>> dispatch(entry_object, "/groups/100001/overview")() | |
'group-100001-overview' | |
>>> dispatch(entry_object, "/groups/100001/members")() | |
'members-of-group-100001' | |
>>> dispatch(entry_object, "/groups/powerby/members")() | |
Traceback (most recent call last): | |
... | |
ValueError: WTF | |
""" | |
current_object = entry_object | |
path_segments = path.lstrip(spliter).split(spliter) | |
for segment in path_segments: | |
#: check access | |
_check_access(current_object) | |
if segment in current_object.exports: | |
#: transform into found public attribute | |
current_object = getattr(current_object, segment) | |
elif hasattr(current_object, "_q_lookup"): | |
#: transform into found dynamic finder | |
current_object = current_object._q_lookup(segment) | |
else: | |
#: failure | |
raise TraversalError("Not found public attribute or dynamic finder") | |
#: check access | |
_check_access(current_object) | |
if callable(current_object): | |
#: final node is function or custom callable object | |
return current_object | |
if hasattr(current_object, "_q_index"): | |
#: final node is module which has an index function | |
return current_object._q_index | |
raise TraversalError("Invalid final handler.") | |
def _check_access(current_object): | |
"""Check the access permission of current object.""" | |
if hasattr(current_object, "_q_access"): | |
current_object._q_access() | |
class TraversalError(Exception): | |
"""Failed to dispatch request by traversal.""" | |
if __name__ == "__main__": | |
import doctest | |
doctest.testmod() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment