Commits

Kevin Chan  committed 4ec6c04

Added Render instance method decorator; moved default render and dispatch methods to BaseApplication.

  • Participants
  • Parent commits 7a9c354

Comments (0)

Files changed (1)

File minipy/application.py

 
 __ALL__ = [
     'BaseApplication',
+    'Render',
 ]
 
 from minipy.settings import (
 
 
 
+### helper functions and classes
+
+class Render(object):
+    """
+    Application instance method decorator to render to template using context.
+    * calls the Application's render method.
+    * reference link:
+
+    http://pycurious.org/2009/11/forget-functions-a-class-based-approach-to-python-decorators/
+
+    How to use:
+
+    * instead of:
+
+    def home(self):
+        '''
+        Render home page.
+        '''
+        template = 'base/home.html'
+        title = u'Hello!'
+        content = u'path: %s' % self.request.path
+        context = {
+            'title': title,
+            'content': content,
+        }
+        return self.render(template, context)
+
+    * use the method decorator:
+
+    @Render('base/home.html')
+    def home(self):
+        '''
+        Render home page.
+        '''
+        title = u'Hello!'
+        content = u'path: %s' % self.request.path
+        return {
+            'title': title,
+            'content': content,
+        }
+
+    """
+    def __init__(self, template):
+        self._template = template
+        self._wrapped = None
+
+    def _render(self, instance, *args, **kwargs):
+        context = self._wrapped(instance, *args, **kwargs)
+        # print 'template: %s' % self._template
+        # print 'context: %s' % context
+        # print 'method: %s' % instance.render
+        return instance.render(self._template, context)
+
+    def __call__(self, wrapped):
+        self._wrapped = wrapped
+        def renderer(instance, *args, **kwargs):
+            return self._render(instance, *args, **kwargs)
+        return renderer
+
+
+### base application class
+
 class BaseApplication(object):
     """
     Application class and wsgi entry point
     request = None
     response = None
     template_dirs = MINIPY_TEMPLATES
-    
+
     def __init__(self, **kwargs):
         """
         Initialize settings and application config.
 
         # initialize template engine
         self._init_tengine()
-        
+
     def __call__(self, environ, start_response):
         """
         Construct environment and run app.
         tengine = self.setting('TENGINE', MakoTemplateEngine)
         template_dirs = self.setting('TEMPLATES', [])
         template_dirs.extend(self.template_dirs)
-        self.template_dirs = template_dirs 
+        self.template_dirs = template_dirs
         self.tengine = tengine(template_dirs=self.template_dirs)
 
     def init_uriconf(self):
     def dispatch(self):
         """
         Dispatch and gather output corresponding to request uri.
-        * subclass should override
+        * default dispatch method.
+        * subclass can override or replace.
         """
-        return u''
+        handler = self.match_uri(self.request.path)
+        try:
+            output = handler.handler()
+        except (AttributeError, TypeError):
+            output = self.not_found()
+        return output
 
     def respond(self):
         """
         return self.response(self.environ,
                              self.start_response,
                              output=output)
+
+    def render(self, t, c):
+        """
+        Utility method to generate output using template engine.
+        * adds default context vars (resources url, settings) to pass to
+          template.
+
+        :param t: template
+        :param c: context
+        :returns: rendered output using self.tengine.render(...)
+        """
+        ctx = {
+            'resources_url': self.setting('RESOURCES_URL', ''),
+            'settings': self.settings
+        }
+        ctx.update(c)
+        context = {'ctx': ctx}
+        return self.tengine.render(template=t, context=context)
+
+    @Render('base/generic.html')
+    def not_found(self):
+        """
+        Render 404 NOT FOUND error page.
+        """
+        return {
+            'title': u'NOT FOUND',
+            'content': u'path: %s' % self.request.path,
+        }