20 mai 2011

Resign Patterns

For all the design patterns lovers...

http://fuzz-box.blogspot.com/2011/05/resign-patterns.html

25 avril 2011

PhpcrCommandsBundle

I started implementing a set of utility commands to manipulate a Jackrabbit content repository from the Symfony2 command console.


The code is on github.

Python MiniMVC

Going further with the concepts exposed in my last post I coded a basic Micro framework for Python running above mod_python for Apache.

MiniMVC is a Python micro MVC framework inspired by Symfony2 from the PHP world.

MiniMVC is lightweighted
MiniMVC uses dependency injection
MiniMVC is configured with YAML
MiniMVC is tested (partially)

MiniMVC features:

A configurable service container
A flexible and configurable request router based on pyroutes
Powerful logging mechanism based on logbook
Basic SQL Alchemy binding
Cheetah and Mako templates, new templating engines can be added very easily

TODO

Don't render the content files through the kernel
Write more tests
Reorganize imports
Configure SQLAlchemy with the ServiceContainer
Generate table classes
Generate entities
Read XML configuration in addition to yaml
More templating engines
...

You can find the code on github.

10 avril 2011

A very simple HTTP server with basic MVC in Python

This is a simple proof of concept of a very simple HTTP server implementing a very basic MVC model (actually only routing and controller) in Python.

We will use the BaseHTTPServer as the web server.

The controller base class


All the controller needs is a reference to the BaseHTTPServer so that it can access the web request and write out the response.

class Controller(object):

    def __init__(self, server):
        self.__server = server

    @property
    def server(self):
        return self.__server

The router


The router needs to manipulate the request and response but also instanciate the controllers, that is why it receives an instance of BaseHTTPServer.

The routes are defined by 3 components:

- A regular expression that must be matched to trigger the route
- A controller class to be instanciated
- A method name to be called on the controller

The tricky part here is to instanciate the controller and call a method on it.

class Router(object):

    def __init__(self, server):
        self.__routes = []
        self.__server = server

    def addRoute(self, regexp, controller, action):
        self.__routes.append({'regexp': regexp, 'controller': controller, 'action': action})
        
    def route(self, path):
        for route in self.__routes:
            if re.search(route['regexp'], path):
                cls = globals()[route['controller']]
                func = cls.__dict__[route['action']]
                obj = cls(self.__server)
                apply(func,(obj, ))
                return

        # Not found
        self.__server.send_response(404)
        self.__server.end_headers()


The request handler


All the request handler needs to do is to instanciate the Router and add to it the routes it needs to manage.

This simple request handler is only able to reply to GET requests.

class MyRequestHandler(BaseHTTPRequestHandler):

    def __init__(self, request, client_address, server):
        
        routes = [
            {'regexp': r'^/$', 'controller': 'HomeController', 'action': 'indexAction'},
            {'regexp': r'^/content/', 'controller': 'ContentController', 'action': 'showAction'}
        ]
        
        self.__router = Router(self)
        for route in routes:
            self.__router.addRoute(route['regexp'], route['controller'], route['action'])

        BaseHTTPRequestHandler.__init__(self, request, client_address, server)
    
    def do_GET(self):
        self.__router.route(self.path)

A simple Hello World controller


class HomeController(Controller):

    def __init__(self, server):
        Controller.__init__(self, server)

    def indexAction(self):
        self.server.send_response(200)
        self.server.send_header('Content-type', 'text/html')
        self.server.end_headers()
        self.server.wfile.write('Hello world')


By the way, in MVC a controller should not do View stuff, see "Going further with a templating engine" below to make the separation better using a view layer.

A controller rendering a file


This controller will serve a file in the "public/" directory. Be carefull there is not enough error checking in this code...

class ContentController(Controller):
    
    CONTENT_BASE_PATH = 'public/'

    def __init__(self, server):
        Controller.__init__(self, server)
        
    def showAction(self):
        filename = ContentController.CONTENT_BASE_PATH + self.server.path[9:]
        if os.access(filename, os.R_OK) and not os.path.isdir(filename):
            #TODO: is there any possibility to access files outside the root with ..?
            file = open(filename, "r")
            content = file.read()
            file.close()
            
            #TODO: set correct content type
            self.server.send_response(200)
            self.server.send_header('Content-type', 'text/html')
            self.server.end_headers()
            self.server.wfile.write(content)
        else:
            self.server.send_response(404)
            self.server.end_headers()

Running the server


What we have defined here is a simple http server that will reply "Hello world" when the URL "/" is accessed, and return the content of a file named myFile (if it exists) when the URL "/content/myFile" is reached.

def main():
    try:
        httpd = HTTPServer(('', 8000), MyRequestHandler)
        print 'Server started...'
        httpd.serve_forever()
    except:
 print 'Server shutting down'
 httpd.socket.close()

if __name__ == '__main__':
    main()

Going further with a templating engine


It is quite simple to integrate a templating engine like Cheetah in this code.

Here is a example of controller rendering a template:

class TemplateController(Controller):

    def __init__(self, server):
        Controller.__init__(self, server)

    def listAction(self):
        self.server.send_response(200)
        self.server.send_header('Content-type', 'text/html')
        self.server.end_headers()
        self.server.wfile.write(Template ( file = 'templates/hello_world.tmpl', searchList = [{ }] ))
        return

Conclusion


That's the reason why I love Python so much, in very few lines we could implement basic MVC over a simple web server.

3 mars 2011

Implement your own phpdoc annotations

The goal is to be able to implement our own phpdoc annotations for custom use.

Access the doc block of a method


...
  $method = new ReflectionMethod('MyClass', 'myMethod');
  $doc = $method->getDocComment();
  ...

A note from the php.net documentation about getDocComment():

In order to retrieve a comment with this method, the comment must be imediately before the class, function or method, start with /** and end with */

Does the method have the annotation?


...
  if (preg_match('/@my_annotation/, $doc) {

    // Do something interesting with $method

  }
  ...

Putting it all together


A function that dumps the public methods of a class unless they are marked with the @ignore annotation:

function listMethods($class_name) {

    foreach(get_class_methods($class_name) as $method_name) {

      $method = new \ReflectionMethod($class_name, $method_name);
      $doc = $method->getDocComment();

      if (! preg_match('/@ignore/', $doc)) {
        echo "$class_name.$method_name";
      }      
    }

  }

PHPUnit - detect failing, skipped and incomplete tests

Sometimes when extending PHPUnit it might be useful to test assertions that are supposed to fail or mark the test as incomplete or skipped. However one wouldn't want the whole test case to fail when testing such assertions. Here is a simple way to achieve this.

Please be warned that this technique should be used carefully in order not to "mask" real failing tests.

To illustrate the method let's write a simple test case extension.

class CustomTestCase extends \PHPUnit_Framework_TestCase {

  // Failing assertion
  public function assertMeantToFail() {
    $this->assertTrue(false);
  }

  // Test incomplete assertion
  public function assertMeantToBeIncomplete() {
    $this->markTestSkipped();
  }

  // Test skipped assertion
  public function assertMeantToBeSkipped() {
    $this->markTestIncomplete();
  }

}

Now we would like to write a test case to check if the above assertions actually do what they are expected to do.

The point is that PHPUnit will use Exceptions to notify the test runner of a failing, skipped or incomplete test. Thus it is possible to intercept the correct Exception to check if the test does what we expect.

class CustomTestCaseTestCase extends CustomTestCase {

  public function testFailingTest() {
    try {
      $this->assertMeantToFail();
    } catch (\PHPUnit_Framework_ExpectationFailedException $ex) {
      // As expected the assertion failed, silently return
      return;
    }
    // The assertion did not fail, make the test fail
    $this->fail('This test did not fail as expected');
  }

  public function testSkippedTest() {
    try {
      $this->assertMeantToBeSkipped();
    } catch (\PHPUnit_Framework_SkippedTestError $ex) {
      // As expected the assertion was skipped, silently return
      return;
    }
    // The assertion did not mark the test skipped, make the test fail
    $this->fail('This test was not skipped as expected');
  }

  public function testIncompleteTest() {
    try {
      $this->assertMeantToBeIncomplete();
    } catch (\PHPUnit_Framework_IncompleteTestError $ex) {
      // As expected the assertion was marked as incomplete, silently return
      return;
    }
    // The assertion did not mark the test incomplete, make the test fail
    $this->fail('This test was not incomplete as expected');
  }

}

The above code is meant to work with PHP 5.3 and namespaces. To make it work on other PHP versions remove the \ at start of the class names.

I should not tell you, but...


Alternately you can use the @expectedException annotation to make a failing test succeed. Although this seems to be a very bad practice, because it can hide problems in your code, I present it here for sake of completeness.

/**
     * This test will succeed !!!
     * @expectedException PHPUnit_Framework_ExpectationFailedException
     */
    public function testSucceed()
    {
        $this->assertTrue(false);
    }

This last method does not work for incomplete or skipped tests.

5 février 2011

Enable CTRL-C / CTRL-V in gnome-terminal

gconftool-2 -t str -s /apps/gnome-terminal/keybindings/copy "c"
gconftool-2 -t str -s /apps/gnome-terminal/keybindings/paste "v"

From http://geekybits.blogspot.com/2007/10/gnome-tip-changing-keyboard-shortcuts.html