diff options
-rw-r--r-- | beweb/beweb/prest.py | 69 |
1 files changed, 68 insertions, 1 deletions
diff --git a/beweb/beweb/prest.py b/beweb/beweb/prest.py index 9a6c337..97ab1d9 100644 --- a/beweb/beweb/prest.py +++ b/beweb/beweb/prest.py @@ -3,9 +3,37 @@ import unittest """A pseudo-REST dispatching method in which only the noun comes from the path. The action performed will depend on kwargs. """ + +class AmbiguousAction(Exception): + def __init__(self, actions): + Exception.__init__(self, "Supplied action is ambiguous.") + self.actions = actions + + +def provide_action(name, value): + def provider(func): + func._action_desc = (name, value) + return func + return provider + class PrestHandler(object): def __init__(self): object.__init__(self) + self.actions = {} + for member in (getattr(self, m) for m in dir(self)): + if not hasattr(member, '_action_desc'): + continue + name, value = member._action_desc + if name not in self.actions: + self.actions[name] = {} + self.actions[name][value] = member + + @classmethod + def add_action(klass, name, value, function): + if name not in klass.actions: + klass.actions[name] = {} + klass.actions[name][value] = function + def decode(self, path, data=None): """Convert the path into a handler, a resource, data, and extra_path""" @@ -23,12 +51,35 @@ class PrestHandler(object): def default(self, *args, **kwargs): child, resource, data, extra = self.decode([None,] + list(args)) - child.dispatch(*([data, resource]+extra), **kwargs) + action = child.get_action(**kwargs) + new_args = ([data, resource]+extra) + if action is not None: + action(*new_args, **kwargs) + else: + child.dispatch(*new_args, **kwargs) + + def get_action(self, **kwargs): + """Return the action requested by kwargs, if any. + + Raises AmbiguousAction if more than one action matches. + """ + actions = [] + for key in kwargs: + if key in self.actions: + if kwargs[key] in self.actions[key]: + actions.append(self.actions[key][kwargs[key]]) + if len(actions) == 0: + return None + elif len(actions) == 1: + return actions[0] + else: + raise AmbiguousAction(actions) class PrestTester(TestCase): def test_decode(self): class ProjectHandler(PrestHandler): + actions = {} def dispatch(self, project_data, project, *args, **kwargs): self.project_id = project_data['project'] self.project_data = project_data @@ -39,6 +90,14 @@ class PrestTester(TestCase): def instantiate(self, project): return [project] + @provide_action('action', 'Save') + def save(self, project_data, project, *args, **kwargs): + self.action = "save" + + @provide_action('behavior', 'Update') + def update(self, project_data, project, *args, **kwargs): + self.action = "update" + foo = PrestHandler() foo.project = ProjectHandler() handler, resource, data, extra = foo.decode([None, 'project', '83', @@ -51,6 +110,14 @@ class PrestTester(TestCase): self.assertEqual(foo.project.kwargs, {'a':'b', 'b':'97'}) self.assertEqual(foo.project.project_data, {'project': '27'}) self.assertEqual(foo.project.resource, ['27']) + foo.default(*['project', '27', 'extra'], **{'action':'Save', 'b':'97'}) + self.assertEqual(foo.project.action, 'save') + foo.default(*['project', '27', 'extra'], + **{'behavior':'Update', 'b':'97'}) + self.assertEqual(foo.project.action, 'update') + self.assertRaises(AmbiguousAction, foo.default, + *['project', '27', 'extra'], + **{'behavior':'Update', 'action':'Save', 'b':'97'}) def test(): patchesTestSuite = unittest.makeSuite(PrestTester,'test') |