Patroon - a Javascript Template Engine

Patroon is a template engine written in Javascript in about 100 lines of code. It takes existing DOM nodes annotated with CSS classes and expand a data object according to simple rules. Additionally you may use traditional string interpolation inside attribute values and text nodes.

Patroon has its own project page now! Please look for current information there.

Example

Comments in this blog are stored as a list of JSON objects, I wrote about it here. So think about a data object like this:

var data = { 
  comment: [{
    date: "2008-09-07 12:28:33", 
    name: "David Beckham",
    website: "beckham.com",
    text: "I watched the euro finals on tv..." 
  }, { 
    date: "2008-09-07 14:28:33", 
    name: "Tuncay",
    website: "",
    text: "Me too"
  }]
};

This data will be expanded with help of following template:

<div class="comments">  
  <div id="comments-template">
    <div class="comment">
      <div class="_ top">
        <a class="_" href="{website}">{name}</a> said
        <a class="_" title="{time}"></a>:
      </div>
      <div class="text"></div>
    </div>   
  </div>
</div>

The javascript to actually execute this template looks like this:

// The comments template will be removed from the DOM!
var template = new Template('comments-template');

// template will result in a new DOM node
var result = template.expand(data);

// insert the resulting node into the comments container
var container = document.getElementsByClassName('comments')[0];
container.appendChild(result);

Using jQuery the code gets a bit cleaner:

// The comments template will be removed from the DOM!
var template = new Template('comments-template');

// Expand the template into the comments section
$('.comments').expand(template, data);

Basic Rules

There are 5 basic rules:

  • Strings and Numbers are inserted by innerHTML to the current node.

  • Arrays repeat the current node and process its elements recursively in same scope.

  • Objects trigger a class name lookup by property name. The value of each property is expanded recursively in new scope.

  • Code will be evaluated for text surounded with braces (Works also for attributes).

  • Processing child nodes will be triggered for nodes with a class attribute starting with _.

I admit the last point is a bit quirky, but processing all child nodes per default is too expensive and too unpredictable. Maybe I will find a better way, but I don’t mind inserting these extra _ class names.

Evaluation

So speaking of the example data, this would mean following algorithm:

  • Find the first node with a class name of comment.

  • Repeat this node two times and recursively process the first and second comment.

  • Descend into the node with class top.

  • Descend into the first link node.

  • Evaluate the code found in the href attribute and in the text.

  • Descend into the second link node.

  • Evaluate the code found in the title attribute.

  • Find the first node with the class text.

  • Insert the the text of the comment into the found node.

Note that we are dealing with two scopes here: the global scope and the comment scope. The global scope just contains a name comment and the comment scope contains the names date, name, website and text.

Download

Download the script at my github repository.

vTouch - Control Ableton Live in a Webbrowser

VTouch is a multitouch browser frontend for Ableton Live. Inside your webbrowser you can control clip triggering, volume, send and return levels, mute, solo, record states. This works also on the network, so you can connect your mobile phone, iPads or android tablets easily by just browsing to you local webserver.

vTouch

Screencast

About the Hack

Ableton Live is an digital audio workstation, which is well suited for live performances. Lots of parameters can be manipulated, midi or audio loops can be triggered. Unfortunately it is cumbersome to use this software with a touch device. A user interface specifically designed to be used on multitouch devices, which is also portable across platforms, offers many benefits and possibilities. Imagine a whole band jamming on iPads with ohne live setup over a wireless network.

Technology used

The frontend is rendered on HTML5 Canvas and communicates with a nodejs server via websockets. On the backend the webserver talks to a running ableton live instance and sends updates to all connected clients.

The canvas frontend is supported on all modern browsers including apple mobile safari and android browsers. We created a small widget library named canvas.ui to take care of multitouch events, rendering and layout management.

RackDAV - Web Authoring for Rack

RackDAV is Handler for Rack, which allows content authoring over HTTP. RackDAV brings its own file backend, but other backends are possible by subclassing RackDAV::Resource.

Install

Just install the gem from github:

$ gem sources -a http://gems.github.com
$ sudo gem install georgi-rack_dav

Quickstart

If you just want to share a folder over WebDAV, you can just start a simple server with:

$ rack_dav

This will start a WEBrick server on port 3000, which you can connect to without authentication.

Rack Handler

Using RackDAV inside a rack application is quite easy. A simple rackup script looks like this:

require 'rubygems'
require 'rack_dav'

use Rack::CommonLogger

run RackDAV::Handler.new('/path/to/docs')

Implementing your own WebDAV resource

RackDAV::Resource is an abstract base class and defines an interface for accessing resources.

Each resource will be initialized with a path, which should be used to find the real resource.

RackDAV::Handler needs to be initialized with the actual resource class:

RackDAV::Handler.new(:resource_class => MyResource)

RackDAV needs some information about the resources, so you have to implement following methods:

  • children: If this is a collection, return the child resources.

  • collection?: Is this resource a collection?

  • exist?: Does this recource exist?

  • creation_date: Return the creation time.

  • last_modified: Return the time of last modification.

  • last_modified=(time): Set the time of last modification.

  • etag: Return an Etag, an unique hash value for this resource.

  • content_type: Return the mime type of this resource.

  • content_length: Return the size in bytes for this resource.

Most importantly you have to implement the actions, which are called to retrieve and change the resources:

  • get(request, response): Write the content of the resource to the response.body.

  • put(request, response): Save the content of the request.body.

  • post(request, response): Usually forbidden.

  • delete: Delete this resource.

  • copy(dest): Copy this resource to given destination resource.

  • move(dest): Move this resource to given destination resource.

  • make_collection: Create this resource as collection.

Note, that it is generally possible, that a resource object is instantiated for a not yet existing resource.

For inspiration you should have a look at the FileResource implementation. Please let me now, if you are going to implement a new type of resource.

RackDAV on GitHub

Download or fork the project on its Github page

Patroon - a Javascript Template Engine (Part 2)

This post is an update to my initial post. Patroon has been improved and is now easier to use and uses a better algorithm internally.

Patroon is a template engine written in Javascript in about 130 lines of code. It takes existing DOM nodes annotated with class names and expand a data object according to simple rules. Additionally you may use traditional string interpolation inside attribute values and text nodes.

The Data

Comments in this blog are stored as a list of JSON objects, I wrote about it here. So think about a data object like this:

var data = { 
  comment: [{
    time: "2008-09-07 12:28:33", 
    name: "David Beckham",
    website: "beckham.com",
    text: "I watched the euro finals on tv..." 
  }, { 
    time: "2008-09-07 14:28:33", 
    name: "Tuncay",
    website: "",
    text: "Me too"
  }]
};

The Template

This data will be expanded with help of following template:

<div class="comments">  
  <div id="comments-template">
    <div class="comment">
      <div class="top">
        {website.length > 0 ? linkTo(name, website) : name} said
        <a title="{time}"></a>:
      </div>
      <div class="text">
        {text}
      </div>
    </div>   
  </div>
</div>

Usage

The javascript to actually execute this template looks like this:

// The comments template will be removed from the DOM!
var template = new Template('comments-template');

// Expand the template into the comments section
$('.comments').expand(template, data);

If you don't want to use jQuery, please look at the end of this article.

Output

The given example renders following output:

<div class="comments">  
  <div id="comments-template">
    <div class="comment">
      <div class="top">
        <a href="http://backham.com">David Beckham</a> said
        <a title="2008-09-07 12:28:33">2 hours ago</a>
      </div>
      <div class="text">
        I watched the euro finals on tv...
      </div>
    </div>   
    <div class="comment">
      <div class="top">
        Tuncay said
        <a title="2008-09-07 14:28:33">1 minute ago</a>
      </div>
      <div class="text">
        Me too
      </div>
    </div>   
  </div>
</div>

Basic Rules

There are 3 basic rules regarding the evaluation:

  • Each found class name of a node will be looked up in the current data object. If found, the node will be processed in the new scope. Example: the class name comment instructs to lookup the name comment in the data object, which contains the comment array.

  • Arrays repeat the current node and process its elements recursively.

  • Code will be evaluated for text surrounded with braces (works also for attributes). The evaluation takes place in the scope of the current data object, which is in the example a comment object. So the snippet <a title="{time}"> will lookup the time in the comment object and insert into the title attribute.

Helper

Code snippets inside the template will be executed within the scope of a Helper object. If you want to extend it, just add your functions to Template.Helper. At the moment it defines only one function:

Template.Helper = {

    linkTo: function(text, url) {
        if (url.indexOf('http://') == -1 && url[0] != '/' && url[0] != '#') {
            url = 'http://' + url;
        }
        return '<a href="' + url +'">' + text + '</a>';
    }

};

Examples

Download

Download the script at my github repository.

Related Work

There are some other libraries for javascript templating, which are related to Patroon:

Patroon is probably the smallest templating solution around and consists only of 130 lines of code.

Appendix

Without jQuery template expansion is a bit verbose:

@@javascript

// The comments template will be removed from the DOM!
var template = new Template('comments-template');

// template will result in a new DOM node
var result = template.expand(data);

// insert the resulting node into the comments container
var container = document.getElementsByClassName('comments')[0];
container.appendChild(result);

Emacs Completions with Hippie-Expand and Snippets

One of the most important features of a text editor is the completing of text inside a buffer. There a lots of packages for Emacs, which provide this feature in many different ways. I will show you, what I use to improve my life as coder.

Multifunctional tab key

Most of the time the tab key in Emacs is bound to the indentation command, which will indent the current line. So if you want to use the tab key for other things, you need some kind of multiplexer, which tries to figure out, what is the right thing to do in each situation.

So I copied the indent-and-complete from the emacs-rails package:

(require 'hippie-exp)
(require 'snippet)

(defun indent-and-complete ()
  "Indent line and complete"
  (interactive)

  (cond
   ((and (boundp 'snippet) snippet)
    (snippet-next-field))

   ((looking-at "\\\\_>")
    (hippie-expand nil))

   ((indent-for-tab-command))))

The function indent-and-complete does one of the following actions:

  • if a snippet is active, it jumps to the next field
  • if we are at a word boundary, it tries to complete with hippie-expand
  • otherwise it indents the current line

HTML mode initialization

Well, this function alone will not change your editor behaviour. For activating our tab function, we need to bind the tab key.

Additionally we want to setup hippie-expand, an expansion package, which will try to expand the word before the cursor in a configurable way. hippie-expand-try-functions-list is a variable, which defines a list of functions, which should be called for completion.

Let's have a look at my html-mode initialization function. It will configure the completion behaviour of hippie-expand an bind the tab key to indent-and-complete.

;; We need a simple wrapper for expand-abbrev
(defun try-expand-abbrev (old)
  (expand-abbrev))

;; ********************************************************************************
;; HTML Mode
;;
(add-to-list 'auto-mode-alist '("\\\\.html\\\\'" . html-mode))

(defun html-mode-on-init ()
  (set (make-local-variable 'hippie-expand-try-functions-list)
       '(try-expand-abbrev
         try-expand-dabbrev))
  (define-key html-mode-map (kbd "<tab>") 'indent-and-complete))

(add-hook 'html-mode-hook 'html-mode-on-init)    

There a two functions, which will be asked to complete the current word:

  • try-expand-abbrev: Expands the current word by looking into the list of defined abbreviations. So called abbrevs are just shortcuts in Emacs. So if you type li and hit the tab key it will be expanded to <li></li>.

  • try-expand-dabbrev: Dynamic abbreviation is a pragmatic method for completing words. Emacs will look for words with the same beginning and use them for completion. Hitting multiple times the tab key will give you different completions, as you may know from the unix shell.

Defining your snippets

Now if you want to use snippets for your html-mode, you have to define a abbrev-table with your desired snippets.

(define-abbrev-table 'html-mode-abbrev-table ())

(snippet-with-abbrev-table 'html-mode-abbrev-table 
 ("h1"      . "<h1>$.</h1>")
 ("h2"      . "<h2>$.</h2>")
 ("h3"      . "<h3>$.</h3>")
 ("h4"      . "<h3>$.</h4>")
 ("h5"      . "<h3>$.</h5>")
 ("h6"      . "<h6>$.</h6>")
 ("div"     . "<div>$.</div>")
 ("divc"    . "<div class=\"$${class}\">$.</div>")
 ("span"    . "<span>$.</span>")
 ("spans"   . "<span style=\"$${style}\">$.</span>")
 ("form"    . "<form action=\"$${action}\" method=\"$${post}\">$.</form>")
 ("input"   . "<input type=\"$${text}\" name=\"$${name}\" value=\"$${value}\"/>")
 ("a"       . "<a href=\"$${href}\">$.</a>")
 ("br"      . "<br/>$.")
 ("ul"      . "<ul>$.</ul>")
 ("ol"      . "<ul>$.</ul>")
 ("li"      . "<li>$.</li>")
 ("tab"     . "<table>$.</table>")
 ("tr"      . "<tr>$.</tr>")
 ("td"      . "<td>$.</td>")
 ("th"      . "<th>$.</th>")
 ("str"     . "<strong>$.</strong>")
 ("em"      . "<em>$.</em>")
 ("meta"    . "<meta name=\"$${name}\" content=\"$${content}\"/>")
 ("style"   . "<style type=\"text/css\">$.</style>")
 ("script"  . "<script type=\"text/javascript\">$.</script>")
 ("scripts" . "<script src=\"$${src}\" type=\"text/javascript\">$.</script>")
 ("img"     . "<img src=\"$.\"/>")
 ("link"    . "<link href=\"$${href}\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\"/>"))

Great. If you put all the code in your .emacs file, you should be able to use your tab key for completions. In our case we defined snippets for the html-mode and activated hippie-expand to use abbrevs and dynamic abbreviation. There is much more stuff I will show you next time, like customizations for other language modes like Ruby and Javascript.

How to write a blog engine in Haskell Part 1

I really like to evaluate programming languages based on their practical value and one of the fun tasks is to write a small static file blog engine. The engine just converts a bunch of markdown files which are sorted into folders by month and year to html files given a set of simple templates.

Top level structure

Basically the rendering of blog posts can be done in three steps:

  • Find all files that contain blog posts
  • Read the markdown files into records
  • Render each file to html and write to disk

In Haskell these steps could be written as:

writeBlog :: IO ()
writeBlog = do
  files <- findFiles "posts"
  posts <- mapM readPost files
  mapM_ writePost posts

When working inside the IO monad, you will use mapM and mapM_ quite often, similar to map they have following type signatures:

mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()

They apply a monadic operation a -> m b to each element of a list and either you want to keep the result of each operation (mapM) or not (mapM_).

Interestingly there is a more generalized version in Data.Traversable:

(Monad m, Traversable t) => (a -> m b) -> t a -> m (t b)

This function applies the monadic operation to anything that is traversable. So you could build a tree data type and declare it as instance of Data.Traversable and use this function to apply the operation while maintaining the tree structure. For example a tree of files would be converted into a tree of blog posts.

Find files

So the first step in the blog rendering process would be to find all files containing a post. So I created a folder named posts which contains folders for each year, which in turn contain folders for each month, which finally contain all the blog posts.

What we want now is the same as the UNIX command find posts -type f.

This can be done by looking at the entries of a folder and entering each sub folder to examine its contents. When we find a file, we collect it into a result list, which will contain all files eventually.

When dealing with tree structures like a file system, recursion is an elegant alternative to iteration. For each folder we find, the function should call itself recursively until it ends up at the bottom most level containing the files.

findFiles :: FilePath -> IO [FilePath]
findFiles path = do
  isFile <- doesFileExist path
  if isFile then
      return [path]
    else do
      entries <- getEntries path
      paths <- return $ map (\ entry -> path ++ "/" ++ entry) entries
      files <- mapM findFiles paths
      return $ concat files
  where
    getEntries filepath = do
      contents <- getDirectoryContents filepath
      return $ filter ((/= '.') . head) contents

findFiles takes a FilePath and returns all files found in this folder or its subfolders. When you pass a file it will just return a list with this one file.

getEntries is a small helper function which returns all entries of a folder without '.' and '..'.

The else branch works like this: it reads all entries of the folder, prepends the current path, recurses for each entry, collects the return values and flattens them into one big list.

Reading posts into records

The data type representing a post is super simple. It just contains the folder (e.g. “posts/2012/12”), the file (e.g. post-title.md) and the text of the post.

data Post = Post { folder, file, text :: String };

readPost therefore takes a FilePath and reads the file contents, decomposing the path name into year, month and filename, which we feed into the record constructor.

readPost :: FilePath -> IO Post
readPost path = do
  s <- readFile path
  let [_, year, month, filename] = splitOn "/" path in
    return Post { folder = year ++ "/" ++ month, file = filename, text = s }

splitOn is taken from the Data.List.Split module in the split package and splits a string into a list of strings given a delimiter string.

To be continued

Next part in this series will take a look at the actual rendering of blog post using the sundown package.