Temple: Compile time, embedded D templates
Dylan Knutson
tcdknutson at gmail.com
Thu Jan 2 00:36:22 PST 2014
On Thursday, 2 January 2014 at 06:59:04 UTC, yazd wrote:
> How much of this is done at compile-time?
Strictly speaking, just the generation of the code that writes
the template to the output buffer. E.g, the code above simulating
the Rails form helper would be lowered to code approximately
equivalent to this (but with more fluff to add line numbers, and
expose some needed hooks for the context):
```
void Temple(OutputStream __buff, TempleContext __context = null)
{
//...
//struct FormHelper, etc
//...
// The actual rendering into a buffer code
auto __buff_tmp_0 = form_for("/shorten", "", (f) {
__buff.put("Shorten a URL: ");
__buff.put(to!string( f.field_for("url") ));
__buff.put(to!string( f.submit("Shorten URL") ));
});
__buff.put(__buff_tmp_0);
auto __buff_tmp_1 = form_for("/person", "person", (f) {
__buff.put("Name: ");
__buff.put(to!string( f.field_for("name") ));
__buff.put("Age: ");
__buff.put(to!string( f.field_for("age") ));
__buff.put("DOB: ");
__buff.put(to!string( f.field_for("date_of_birth", "date") ));
__buff.put(to!string( f.submit ));
});
__buff.put(__buff_tmp_1);
}
```
>I would guess that
> the code is compiled but it is evaluated on each render. Is
> that correct? Is there a way to force compile-time evaluation
> of at least part of the template which does not depend on a
> runtime value?
Yes, generated templates themselves can be executed with CTFE
(just had to make a small modification to ArrayOutputAppender,
which has been pushed), as long as they don't take a context. The
reason for this is that std.variant.Variant isn't CTFEable,
because it uses memcpy in opAssign. I'd consider that a Phobos
bug; perhaps there is a way to make std.variant CTFE compatible?
That'd allow for a much wider (and more useful) range of
templates to be evaluated at compile time.
Anyways, here's a working compile time evaluated, compile time
generated template:
```
string templeToString(TempleFuncType* func, TempleContext context
= null)
{
auto accum = new AppenderOutputStream;
(*func)(accum, context);
return accum.data;
}
unittest
{
alias render = Temple!q{
<% if(true) { %>
Bort
<% } else { %>
No bort!
<% } %>
<% auto a = capture(() { %>
inside a capture block
<% }); %>
Before capture
<%= a %>
After capture
};
const result = templeToString(&render);
static assert(isSameRender(result, `
Bort
Before capture
inside a capture block
After capture
`));
}
```
More information about the Digitalmars-d-announce
mailing list