lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Tue, Jan 19, 2010 at 5:20 AM, Tobias Kieslich <tobias@justdreams.de> wrote:

> I very much like the idea of scripting templates because it comes
> naturally to the coder. (...)

Yes, I have this point of view now.

> I have to parse the XML anyway, so I get the attributes and their
> values. That's rather straight forward. If the user hands me garbage I
> let the interpreter or the VM complain. Makes for ugly debugging, but I
> can work on that later to make it easier.

I think the worst part is matching lines: where the user declared the
tag, and where the code generator puts the associated
expression/statement. With the template-is-a-Lua-script approach, it's
somewhat hard to identify in what line  an expression is, because
whilst you can check with the debug library what line the tag function
was called, you can't tell which line the attribute is being declared
( span{ \n\n href="${ obj:link_to( 'blog' ) }" } ). Perhaps with a
proper XML parser this can be made easier.

>> Although I just did a quick glance at your code I see that you use a
>> table for holding the output, and then concatenates at the exit point.
>> Our code generator expects a vararg function to be called (named
>> "out") that, well, outputs the generated (x)html. The code generator
>> tries to optimize constants by concatenating adjacent strings and
>> automatically sanitize dynamic expressions.
> This is something that I might try to implement later, especially since
> wsapi expects a yieldable coroutine.(...) So I
> just went for a buffered application output, let the server send chunks
> as large as it likes and have the gc clean up(...)

I've thought of something similar, it is way simpler to just buffer
all the output, or to send each buffer as it is available. However,
there are some pages that are too big. too slow to generate or both.
IMO, one alternative is to buffer all sequential statements of a block
and output at it's end. More specifically, before each "end", be it
belonging to an "if" or "for", call a "flush" command and let the
webserver decides if it wants to buffer everything or not. This is
just an idea, tough; I've not tested it yet.

>> ~~ template.lua
>>
>> return
>> html{
>>   head{ title 'My Website - Under construction' },
>>   body{
>>     p{
>>       _for = 'i = 1, 10',
>>       span{ class = '${ i % 2 == 0 and "odd" or "even" }',
>>         'Hello, ${ i } world'
>>       }
>>     }
>> } }
Proprietary, but not something really new.

>> Do you plan to implement a forelse special attribute (i.e: if the loop
>> never enters, then the "else" value shall be evaluated). If so, with
>> what semantics?
> Hm, if I get you right, you mean an empty table so it never loops, so I
> wanna display another element. I think that can be done with tools
> on board, even if not really pretty.

Not only empty tables, but an empty iterator:

~~
<pre>
<div l:for="line in io.open( 'file.txt' ):lines()">
${ line }
</div>
</pre>
~~

On our templating, you can specify a _forelse special attribute
containing, or the enclosing tag, or the inner content, depending
whether the value is a simple table or a tag[1]:

~~
pre{
  div{
    _for = 'line in io.open( "file.txt" ):lines()',
    _forelse = "Sorry, kiddo. Empty file",
    '${ line }',
  }
}
~~
out( '<pre>' )
do local __RUN = false
for line in io.open( "file.txt" ):lines() do
  __RUN = true
  out( '<div>',__sanitize( line ), '</div>\n' )
end
if __RUN == false then
    out( '<div>Sorry, kiddo. Empty file</div>' )
end
end
out( '</pre>' )
~~

I'm also considering to implement a _forfirst and _forlast, but am
afraid of becoming too clunky and having to extend the syntax
(_forfirst and _forlast would have to be elements/tags instead of
attributes).

--rb

[1] A tag contains it's name on index zero of the resulting table:
div{ "ok" } --> { [0] = "div", "ok" }