Brevé vs Myghty

To give a feel for how Brevé looks compared to other template engines, I've converted the Pylons QuickWiki tutorial to Brevé and provided the original Myghty templates for comparison.

Notes

You may wonder why the Brevé template isn't always shorter. This is mostly due to Brevé's explicit inheritance style which adds around 4 lines per template. While not shown here, this explicit style allows for a flexible inheritance mechanism. Regardless of actual line count, the Brevé templates are typically much typographically cleaner and easier to read than the equivalent Myghty template. This particular example may have been a bit unfortunate since it fails to showcase some of Brevé's more interesting features, but I'm sure the same could be said of Myghty, so for the sake of simplicity I'm willing to live with that.

It should also be noted that I made a couple cosmetic changes to the Myghty templates, splitting tags over lines for both the sake of readability and to closer match my own style in Brevé. This seemed most fair to both (otherwise the Myghty templates appeared less readable and the Brevé templates appeared to have higher line counts). The goal is to compare template engines, not a particular programmer's style. The original templates are otherwise unaltered from the tutorial.

Note that web helpers that output XML must be surrounded by xml ( ) as this prevents their output from being quoted.

Finally, the original tutorial builds some of the templates in multiple steps. For the sake of brevity I've already completed all the steps and provide the finished examples.

The main template

Myghty (templates/autohandler):

<html>
    <head>
        <title>QuickWiki</title>
        <% h.stylesheet_link_tag('/quick.css') %>
        <% h.javascript_include_tag('/javascripts/effects.js', builtins=True)  %>
    </head>
    <body>
        <div class="content">

% m.call_next()

        <p class="footer">
          Return to the
          <% h.link_to('FrontPage', h.url_for(action="index", title="FrontPage")) %>
% if h.url_for() != '/page/list':
           | <% h.link_to('Edit '+c.title, h.url_for(title=c.title, action='edit')) %>
           | <% h.link_to('Title List', h.url_for(action='list', title=None)) %>
% # end if
</p>

        </div>
    </body>
</html>

Brevé (templates/index.b):

html [
    head [
        title [ 'QuickWiki' ],
        h.javascript_include_tag('/javascripts/effects.js', builtins=True)
    ],

    body [
        div ( class_="content" ) [

            slot ( 'content' ),

            p ( class_="footer" ) [
                'Return to the ',
                h.link_to ( 'FrontPage', h.url_for ( action="index", title="FrontPage" ) )
                '|', h.link_to ( 'Edit ' + c.title, h.url_for ( title=c.title, action='edit' ) ),
                '|', a ( render = c.render.list_link, data = h.url_for ( ) )
            ]
        ]
    ]
]

Note the use of the custom renderer in the footer. You can see how this is setup in controllers/page.py which is listed at the end of this document.

The page template

Myghty (templates/page.myt):

<h1 class="main"><% c.title %></h1>
% if c.message:
<p><div id="message"><% c.message %></div></p>
% #end if

<% c.content %>

Brevé (templates/page.b):

inherits ( 'index' ) [
    override ( 'content' ) [
        h1 ( class_ = 'main' ) [ c.title ],
        p ( render = c.render.message, data = c.message ),

        xml ( c.content )
    ]
]

We're also using a custom renderer in this template. See the controller at the end of this document for more information.

The new page template

Myghty (templates/new_page.myt):

<h1 class="main"><% c.title %></h1>
<p>
   This page doesn't exist yet.
   <a href="<% h.url_for(action='edit', title=c.title) %>">
       Create the page
   </a>.
</p>

Brevé (templates/new_page.b):

inherits ( 'index' ) [
    override ( 'content' ) [
        h1 ( class_="main" ) [ c.title ],
        p [
            'This page doesn't exist yet.',
            a ( href=h.url_for ( action='edit', title=c.title ) [
                'Create the page.'
            ]
        ]
    ]
]

The edit template

Myghty (templates/edit.myt):

<h1 class="main">Editing <% c.title %></h1>

<% h.start_form(h.url_for(action='save', title=c.title), method="get") %>
    <% h.text_area(name='content', rows=7, cols=40, content=c.content)%> <br />
    <% h.submit(value="Save changes", name='commit') %>
<% h.end_form() %>

Brevé (templates/edit.b):

inherits ( 'index' ) [
    override ( 'content' ) [
        h1 ( class_="main" ) [ 'Editing ' + c.title ],

        form ( action = h.url_for ( action='save', title=c.title ), method="get" ) [
            textarea ( name='content', rows='7', cols='40' ) [ c.content ],
            input ( type='submit', value='Save changes', name='commit' )
        ]
    ]
]

The titles template

Myghty (templates/titles.myt):

<h1 class="main">Title List</h1>

<div id="trash">
    Delete a page by dragging its title here
</div>
<% h.drop_receiving_element("trash", update="titles", url=h.url_for(action="delete")) %>

<ul id="titles">
  <% render('/list.myt', fragment=True) %>
</ul>

Brevé (templates/titles.b):

inherits ( 'index' ) [
    override ( 'content' ) [
        h1 ( class_='main' ) [ 'Title List' ],

        div ( id="trash" ) [
            'Delete a page by dragging its title here'
        ],
        xml (
            h.drop_receiving_element ( "trash", update="titles", url=h.url_for ( action="delete" ) )
        ),

        include ( 'list' )
    ]
]

The list template

Myghty (templates/list.myt):

% for title in c.titles:
<li>
    <span id="page-<% title %>"><% title %></span>
    [<% h.link_to('visit', h.url_for(title=title, action="index")) %>]
    <% h.draggable_element("page-"+ str(title), revert=True) %>
</li>
% #end for

Brevé (templates/list.b):

ul ( id="titles" ) [
    [ li [
        span ( id='page-%s' % t ) [ t ],
        '[', h.link_to ( 'visit', h.url_for ( title=title, action='index' ) ), ']',
        h.draggable_element ( 'page-%s' % t, revert=True )
    ] for t in c.titles ]
]

Note that a direct mapping of this template wasn't possible since Brevé templates must be complete sections. That is, there must be a single enclosing tag at the topmost level. The Myghty template could have been easily altered to have the <ul> tag in the fragment but I think it's an important point to note, so I left the distinction visible.

The controller class

This is more or less the same as the one for Myghty, but there are a couple changes and I needed to show the custom renderers, so it's included here for completeness.

Brevé controller (controllers/page.py):

from quickwiki.lib.base import *
from quickwiki.lib.database import session_context
from breve.tags import html as H

class Class: pass
class PageController ( BaseController ):
    def __before__ ( self ):
        c.render = Class ( )
        c.render.message = self.render_message
        c.render.list_link = self.render_list_link
        self.session = session_context.current
        self.query = self.session.query ( model.Page )

    def index ( self, title ):
        page = self.query.get_by ( title=title )
        if page:
            c.content = page.get_wiki_content ( )
            return render_response ( 'page' )
        elif model.wikiwords.match ( title ):
            return render_response ( 'new_page' )
        abort ( 404 )

    def edit ( self, title ):
        page = self.query.get_by ( title=title )
        if page:
            c.content = page.content
        return render_response ( 'edit' )

    def save ( self, title ):
        page = self.query.get_by ( title=title )
        if not page:
            page = model.Page ( )
            self.session.save ( page )
            page.title = title
        page.content = request.params [ 'content' ]
        c.title = page.title
        c.content = page.get_wiki_content ( )
        c.message = 'Successfully saved'
        self.session.flush ( )
        return render_response ( 'page' )

    def list ( self ):
        c.titles =  [ page.title for page in self.query.select ( ) ]
        return render_response ( 'titles' )

    def delete ( self ):
        title = request.params [ 'id' ][ 5: ]
        page = self.query.get_by ( title=title )
        self.session.delete ( page )
        self.session.flush ( )
        c.titles = self.query.select ( )
        return render_response ( 'list', fragment=True )

    # a couple custom renderers
    def render_message ( self, tag, data ):
        if data:
            return tag [
                H.div ( id="message" ) [ data ]
            ]
        return ''

    def render_list_link ( self, tag, data ):
        if data == '/page/list':
            return ''
        return tag [ h.link_to ( 'Title List', data ) ]

I've provided an archive of the Brevé templates and controller to make it easier to play with. It isn't the entire project, just the notable differences.

edit page
Back to top
Rendered using Brevé 1.2.8Copyright © 2007, Cliff Wells