Skip to:

Tiago Cogumbreiro

O Irrepupável

Back to top

Method Component

Peak is it's component system. In this article I will guide you through a real life example on how to take advantage of it to defeat a common OOP problem that cannot be solved through class extension cleanly, especially on languages based on one extension per class like Java.

I am developing web applications that need to show to the user tables of a database. So you can think of it as objects that need some kind of view (or other operations). The generic method for doing this is:

# some class method
    @managed
    @secure
    def view (self, id, **kwargs):
        entry = self._getEntry (id)
        tpl_vars = self._fillViewTemplate (entry)
        tpl = self.ViewEntry (searchList=[tpl_vars])
        return str (tpl)

This method has two decorators @managed which means this is a method visible as a webpage - the returning string will be dumped in the browser - and a @secure which means that to access this method you need some kind of permission.

Now the interesting part comes in the core of the method, we have the generic way of how a view method should be defined:

  1. get the object from the database: self._getEntry (id)
  2. get the view associated with this object: tpl = self.ViewEntry (searchList=[tpl_vars])
  3. return the rendered view: return str (tpl)

This is a generic method that depends on a few existing methods on the class it is defined:

  • _getEntry: a method that returns the object that the "user" wants to view
  • _fillViewTemplate: a method that returns a number of variables that is going to be used in the object view
  • ViewEntry: returns a rendered webpage that shows your object

Now image we have a view, delete, edit and create. One could easely create an extended that just needed to define the methods that they depend. The problem starts when you just need one of these methods, extending the class would mean you would've inherited all the methods the parent class has. To correct this we can create callable components that act just as real methods.

from peak.api import *
ViewEntryTemplate = PropertyName ("mypackage.templates.ViewEntryTemplate")
class ViewMethod (binding.Component):
    _getEntry = binding.Obtain ("../_getEntry")
    _fillTemplate = binding.Obtain ("../_fillViewTemplate")
    ViewEntry = binding.Obtain (ViewEntryTemplate)
    @managed
    @secure
    def __call__ (self, id, **kwargs):
        entry = self._getEntry (id)
        tpl_vars = self._fillViewTemplate (entry)
        tpl = self.ViewEntry (searchList=[tpl_vars])
        return str (tpl)

To use this component is easy:

class MyApp (binding.Component):
    view = binding.Make (ViewMethod)
    def _getEntry (self, id):
        """We should return an entry here"""
    def _fillViewTemplate (self, entry):
        """We should return a list of variables to be used in the template here"""
        return {}

Now to use this method your class needs to offer: a _getEntry and _fillViewTemplate methods (just as before) but you managed to decouple the ViewEntry variable, which is related to the ViewMethod alone. We are also using a property to define the template, so it can be defined in the configuration of your application.

Summing it all up, we were able to provide greater flexibility, removed some unneeded variables (ViewEntry) from our base class and can now use just the needed methods.


Tags used:

Back to top