Source

vlastic / vlastic / rom / resource.py

Full commit
from .. import http

__all__ = ["Resource", "ObjectResource", "DictionaryResource"]

METHOD_HANDLER_ATTRIBUTE_NAME = "\nrom_methods\n"


class Resource:
    """Resource accepts a request and returns a response.

        class SessionStore(vlastic.rom.Resource):
            @vlastic.rom.get
            def get_user(self):
                return {"name": ...}

            @vlastic.rom.post
            @vlastic.rom.put
            def login(self, name, password):
                ...

            @vlastic.rom.delete
            def logout(self):
                ...

    When sess = SessionStore(), it RESTfully maps to HTTP. See also following
    table:

        +----------------------------+----------------------+
        | HTTP                       | Python object        |
        +----------------------------+----------------------+
        | GET /                      | sess.get_user()      |
        | POST /?name=a&password=b   | sess.login("a", "b") |
        | PUT /?name=a&password=b    | sess.login("a", "b") |
        | DELETE /                   | sess.logout()        |
        +----------------------------+----------------------+

    """

    def __call__(self, request):
        if tuple(request.path) != ():
            return http.NotFoundError()
        method_name = request.method.upper()
        for attr in dir(self):
            method = getattr(self, attr)
            if hasattr(method, METHOD_HANDLER_ATTRIBUTE_NAME):
                names = getattr(method, METHOD_HANDLER_ATTRIBUTE_NAME)
                if method_name in names:
                    return method()
        return http.MethodNotAllowedError()


class ObjectResource(Resource):
    """ObjectResource is the resource which be able access childs with
    same way of handling object attributes. 

    """

    def __call__(self, request):
        path = request.path
        try:
            child_name = next(path)
        except StopIteration:
            return Resource.__call__(self, request)
        if hasattr(self, child_name):
            return getattr(self, child_name)(request)
        return http.NotFoundError()


class DictionaryResource(Resource):
    """DictionaryResource is the resource which be able access childs by
    same way of handling dict.
    
    """

    def __call__(self, request):
        path = request.path
        try:
            child_name = next(path)
        except StopIteration:
            return Resource.__call__(self, request)
        try:
            child = self[child_name]
        except KeyError:
            return http.NotFoundError()
        return child(request)

    def __getitem__(self, child_name):
        return self.child[str(child_name)]

    def __setitem__(self, child_name, child):
        if not hasattr(self, "child"):
            self.child = {}
        self.child[str(child_name)] = child

    def __delitem__(self, child_name):
        del self.child[str(child_name)]