template engine [ was: Re: Implementing tables - advice wanted ]

Joe Armstrong (AL/EAB) joe.armstrong@REDACTED
Wed Jun 14 11:56:54 CEST 2006


I see no reason why a template engine should offer any other than
full access to all Erlang functions, not some ad-hock subset.


My template engine is described here:

http://www.erlang.org/ml-archive/erlang-questions/200602/msg00326.html 

I've edited some comments into Gaspar's mail at the end of this post.

	<? map
Since this posting I have done one or two experiments - all failed
so I stand by the original design.

I also came up with a small (and useful) "mini template".

Since it is instructive, I can relate what happened when I tried to
improve upon the original design.

- I made two attempts to "improve" my design
	1) make a restricted template language (like velocity)
	2) make something A lot like PHP

What happened?

1)

I did something like velocity - but I very soon missed
the power of a full programming language - doing easy thing was,
well .. uuug easy - doing other things was complex and doing
difficult things was ... impossible.

Embedding ajax calls using higher order functions - forget it ...

I junked this experiment

2) I thought "this (ie my template engine) is pretty much like PHP
let's make it even more like PHP to attract users who know PHP.

To do this I added an out(String) primitive and changed the semantics of
my 
template language.

< aside >
I have to briefly explain the semantics of my original template
language:

   <h1>hello</h1>
   <? N = 10, "" ?>
   <p>Factorial <? N ?> is <? fac(N) ?>

This means "create a string"

	"<h1>hello</h1> ++ "" ++ "<p>factorial N is" ++
coerce_to_string(N) ++ " is " ++ ...

is the LAST value is a <? .. ?> is coerced into a string and the value
is
pasted into the document. Bindings created *within* <? ... ?> get
carried to the
next <? ... ?> context.
</aside>

My new language (inspired by PHP) was more like this:

    <h1>hello</h1>
    <? N = 10 ?>
    <p>factorial <? out(N) ?> is <? out(fac(N)) ?>

Which was transformed into:

	out("<h1>hello</h1>"),
	N = 10,
	out("<p>factorial ");
	out(N),
	out(" is "),	
	out(fac(N))

At the time I rather liked this - all I had to do was enclose
top level bits of HTML in an out(...) wrapper.

Then my subroutines could also call out(...) - like PHP

This resulted in a soggy mess. Why? - evaluation order now matters.
I/O is an imperative side effect, scattering out(X) statements at random

in subroutines implies that somehow and somewhere you have an idea as to

in which order these subroutines will be called.

Pure functional programming is far easier - in the earlier model
each function returns a string (if that's what you want) and the caller
assembles the
return values into new strings. The order of calling the routines is
irrelevant,
since you will always get the same result.

I/O by side effects (using out(X) in a subroutines) made writing all 
other than simple code a mess.

I junked this experiment.

To recap - If I had distributed experiment 1 (the velocity approach) I
would
have committed a venial sin, resulting in "temporary loss of grace" from
the
Erlang Users. But distributing something with a PHP like syntax would be
a mortal
sin requiring a valid confession in articolo mortis - and what would
happen if
I met an untimely end, like in a car crash, so that I couldn't confess
...

So we're back to my original design.

In passing I did make a little mini-mini-template language.

This is simply HTML with a few ${Var} variables in it - like this:

Put this in a file foo.template

	<title>${title}</title>
	<h1>hello ${person} how are you?


Then expand with:

	expand:file("foo.template", [{"title", "my web page"},
	                             {"person", "joe"}]).

Or make an xml template instance (say in the file bar)

	<title>my web page</title>
	<person>joe</person>

and expand with:

	expand_xml("bar!", "foo.template")	
	
This mini-mini-template language which is laughably simple, 
is *very useful*.
	
 
/Joe


 


> -----Original Message-----
> From: owner-erlang-questions@REDACTED 
> [mailto:owner-erlang-questions@REDACTED] On Behalf Of 
> Gaspar Chilingarov
> Sent: den 13 juni 2006 23:23
> To: Erlang Users' List; ke han
> Subject: RFC: template engine [ was: Re: Implementing tables 
> - advice wanted ]
> 
> Hello all!
> 
> Post directed mainly to ke han, but all other list members are welcome
> -- You have mentioned html template engine for erlang - what 
> kind of features do you like in there ?
> 
> For current moment I got some simple engine which provides 
> following templating commands -
> 
> <%TRANSLATE atom%>  - generate string, calling some 
> translation function (to make multilangual sites)
> 

     <? translate(atom) ?>

> <%FOREACH keyname%> - <%/FOREACH%> - take element keyname 
> from proplist (which should have list value) and iterate 
> inner part of FOREACH loop for each element in that list.

     <? map(fun foo/1, L) ?>  with an external function, or

	<? map(fun(I) ->
	         ["<h1> ...", I , ... ]
	       end, L) ?>


> <%WITH keyname%> <%/WITH%>- just go one level deeper - fetch 
> one element from proplist and execute inner template with it

    I don't understand - possibly

	<? someFunc(dict:lookup(keyname, D)) ?>


> 
> <%PUT keyname%> - just put element of proplist into current position.

    <? D1 = dict:store(keyname, Val, D), "" ?> (note the extra "" :-)

> <%PUTVALUE%> - if we are in a leaf node - put it's value into 
> current position - ether string or integer.

    ??????

> so
> if you have template
> <%FOREACH args%><%PUTVALUE%> <%/FOREACH%>
> 
> and we feed templating function with
> {struct, [
> 	{args, {array, ["Hello", "world", "!"]} } ]} data we 
> will receive "Hello world ! " string.
> 
> this approach - added with if/ifdef/else commands allows 
> create templates which are totally separate from programming 
> language and are driven only by data which is fed to template 
> interpreted.
> 
> it somehow resembles XSLT, but much more simple to allow HTML 
> designers easily use it and put into pages without disturbing 
> programmer too much.
> 
> second idea with such markup is that there is translator from 
> such markup to JSON notation, and there is JS template 
> renderer, which could be run on client machine - thus 
> allowing passing from server not rendered template, but 
> parsed template and data -- JS copes well even on slow 
> machines with datasets about up to 1000 elements  - like 
> 10x100 table - which is practically enough for most tasks.
> 
> 
> solution, which you would like to see - even too fantastic or 
> futuristic -- because it's always possible to find something 
> reasonable and practical there.
> 
 

> 
> Looking forward for answers :)
> 
> --
> Gaspar Chilingarov
> 
> System Administrator,
> Network security consulting
> 
> t +37493 419763 (mob)
> i 63174784
> e nm@REDACTED
> 



More information about the erlang-questions mailing list