Joshua Morey | 2014-01-27

Skhema Filters

I finally decided on a syntax, so Skhema now has filter support. As a result, I have updated Bramble by moving the markdown parser references from models to views (where they always belonged). Skhema templates can now use filters on variables like {$var:filter[key1,key2=val]}, where brackets contain the optional filter parameters. This is shown in the following template that Bramble uses during the rendering of this post.

{@PageSection}
<div class="article">
<div class="title">
<h2><a href="{$url}">{$title}</a></h2>
</div>
<div class="post">
<div class="entry">
{$content:subvert[code,root,header=3]}
</div>
</div>
</div>
{/@}

The subvert filter handler needs to be registered with the TemplateManager, and any applicable filter options are the responsibility of the filter handler. From this example template, the Subvert renderer enables code formatting, sets a root URL for relative URL handling, and sets the current header level at h3 (because the page design already uses h1 and h2).

TemplateManager::RegisterFilter('subvert', function($var, $filter_options, $context) {
// handle options
// ...
return Subvert::Parse($var, $options);
});

I added user-defined function handlers, in addition to filters, because they use the same mechanism. I just don't have any use-cases for them at this time.

Joshua Morey | 2014-01-24

Skhema Functions

The initial support for functions in Skhema was more for test purposes than anything else. I haven't had any need for functions in my current framework, but I imagine that I probably will at some point. I made sure that they fit into the language design that I was finalizing, but I left the implementation as an inefficient late-evaluation.

I had initially thought that the best approach would be to compile functions during the graph-generation phase, but I have decided instead to compile functions during the evaluation phase and just do a proper lazy evaluation. Compiling during graph-generation would unnecessarily complicate the serialization process with proxy objects that don't improve the situation. A more serious issue is that the graph generator doesn't necessarily know if a particular function will be legal during evaluation. This is an unfortunate side effect of the way I change context scope for data-binding. I will continue to think about this issue.

Here is a contrived example showing the most basic functions: {%iteration} and {%cycle}. I say "contrived" because this can be done with CSS3 or any JavaScript library ever. Technically, the iteration index doesn't need to be a function, but I like the syntax for it. As a current implementation detail, {%iteration} can be written instead as {$__iteration}, but I wouldn't be surprised if that changed.

<table>
{?list}
<tr style="background-color:{%cycle=white,LightGray}">
<td>{%iteration}</td>
<td>{$url}</td>
</tr>
{/}
</table>

I am also still trying to figure out the syntax I want to use for filters, so that I can move logic like markdown rendering from the model to the view, which is more appropriate.

One of the next things I will work on is a proper page cache. Right now, full page renders cost 20-60 ms (depending on the page). That's a bit much even for this slow Dreamhost shared server with no bytecode caching. Almost all of the time is the database queries, so a simple cache should get me back below 20 ms for all pages.

Joshua Morey | 2014-01-24

Merging Personal Blog

I am dismantling my personal blog that I had at joshmorey.com. As expected, based on previous attempts, it didn't get much love from me, so for now I will go ahead and post my one personal entry per year here instead. Deal with it.

I'll start things off by recyling an old image from that blog, back when I did the Thursday Night Ride.

Joshua Morey | 2014-01-17

Skhema Templating Engine

In my last post, I wrote about my new templating engine. As I mentioned, the main unknown at the time was whether the language would adequately cover my use-cases. Since then, I have integrated it into the MVC framework of the Bramble Web Application Framework, and I am very satisfied with the results. As part of the integration, I changed the project name from templ@te to Skhema, since the old name was not web-friendly. This site is now running on Bramble using Skhema for rendering models.

The language has not changed much since last year. My concern was mostly with making sure that it was a good design, but I did find time for a few things. I improved the deserialization performance and provided alternate serialization modes. I improved the graph evaluation performance, and added preliminary function support. Functions are my primary extension-point at the moment, but they aren't particularly fast yet because the graph does an inefficient late-evaluation. All I have at this point are some basic operations like iteration index and cycle, but once I get back to this project I will properly generate the graph nodes for functions and add support for more powerful operations and user extensions.

<table>
{?list}
<tr class="{%cycle=odd,even}">
<td>{%iteration}</td>
<td><a href="{$url}">{$name}</a></td>
</tr>
{/}
</table>

For now, functions are scope-limited. I haven't decided on a syntax yet for accessing the functions of the outer list from the following example.

{?outer}
{?inner}
{%iteration}<br>
{/}
{/}

I didn't cover this in my last post, but one of the main differences that Bramble has from many other PHP templating engines is that mine does not compile to PHP statements, but rather to a graph that is evaluated using the data binding source. Originally, I had intended the graph/tree to be an intermediate structure that would get converted to PHP code for evaluation. Surprisingly, however, the graph evaluation proved to be faster than the alternative template engines that I was using for comparison, so I decided to simply serialize the graph instead.