diff --git a/src/milla/controllers.py b/src/milla/controllers.py index 1384552..1a5bcd7 100644 --- a/src/milla/controllers.py +++ b/src/milla/controllers.py @@ -88,3 +88,42 @@ class FaviconController(Controller): datetime.timedelta(days=self.EXPIRY_DAYS)) response.headers['Expires'] = milla.util.http_date(expires) return response + + +class HTTPVerbController(Controller): + '''A controller that delegates requests based on the HTTP method + + Subclasses of this controller should have an instance method for + every HTTP method they support. For example, to support the ``GET`` + and ``POST`` methods, a class might look like this: + + .. code-block:: python + + class MyController(HTTPVerbController): + + def GET(self, request): + return 'Hello, world!' + + HEAD = GET + + def POST(self, request): + return 'Thanks!' + + This example also allows ``HEAD`` requests, by processing them as + ``GET`` requests. *Milla* handles this correctly, as it does not + send a response body for ``HEAD`` requests, even if the controller + callable returns one. + ''' + + def __call__(self, request, *args, **kwargs): + try: + func = getattr(self, request.method) + except AttributeError: + raise milla.HTTPMethodNotAllowed + return func(request, *args, **kwargs) + + @property + def allowed_methods(self): + for attr in dir(self): + if attr.upper() == attr: + yield attr