<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>hyperstruct &#187; Erlang</title>
	<atom:link href="http://hyperstruct.net/category/tags/erlang/feed/" rel="self" type="application/rss+xml" />
	<link>http://hyperstruct.net</link>
	<description>{do flatlanders dream of n-dimensional shapes?}</description>
	<lastBuildDate>Sat, 08 May 2010 15:37:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.5</generator>
		<item>
		<title>Dynamic variables hack in Erlang</title>
		<link>http://hyperstruct.net/2008/01/31/dynamic-variables-hack-in-erlang/</link>
		<comments>http://hyperstruct.net/2008/01/31/dynamic-variables-hack-in-erlang/#comments</comments>
		<pubDate>Thu, 31 Jan 2008 10:23:53 +0000</pubDate>
		<dc:creator>bard</dc:creator>
				<category><![CDATA[Documentation]]></category>
		<category><![CDATA[Erlang]]></category>

		<guid isPermaLink="false">http://hyperstruct.net/2008131dynamic-variables-hack-in-erlang/</guid>
		<description><![CDATA[<p>One thing that jumps to the eye in functional code sources
is longer-than-usual argument lists.</p>

<pre>
<code>
process(Tree, Env, Plugins, Config, ...).
</code>
</pre>

<p>It's easy to see that as a consequence of functions using arguments as sole
input channel.  (Global <code>-define()</code>'s
don't qualify as input channels&#8212;they can't vary at runtime, arguments can.)</p>

<p>Usually it's no big hassle.</p]]></description>
			<content:encoded><![CDATA[<p>One thing that jumps to the eye in functional code sources is longer-than-usual argument lists.</p>
<pre><code>
process(Tree, Env, Plugins, Config, ...).
</code>
</pre>
<p>It&#8217;s easy to see that as a consequence of functions using arguments as sole input channel.  (Global <code>-define()</code>&#8216;s don&#8217;t qualify as input channels—they can&#8217;t vary at runtime, arguments can.)</p>
<p>Usually it&#8217;s no big hassle.</p>
<p><!--break--></p>
<p>Sometimes though you have a front-end function to a complex computation which is arranged in many layers of function calls, and you need to pass something to the front-end that only the lowest layer needs. You&#8217;d rather to not care about it in intermediate layers, but you still have to because intermediate layers forward it to the lowest one.</p>
<p>Obligatory contrived example (if you can read Ruby, Dave Thomas has a <a href="http://pragdave.blogs.pragprog.com/pragdave/2003/06/dynamically_sco.html">better one</a>):</p>
<pre><code>
%% User invocation
library:do_it(A, B, C, D).

%% Library
do_it(A, B, C, D) -&gt;
    part1(A) ++ part2(B, C, D).

part2(B, C, D) -&gt;
    extra_computation(B) ++ part3(C, D).

part3(C, D) -&gt;
    another_extra_computation(C) ++ part4(D).

%% ...
</code>
</pre>
<p>Above, <code>D</code> isn&#8217;t really needed until <code>part4</code>, but <code>part1</code>, <code>part2</code> and <code>part3</code> have to accept it as argument.</p>
<p>Functions being unable to see beyond their argument list spares me many a headache compared to when I dwell in OO-land, so I tend to deem it a <em>feature, not a bug</em>.  In cases like the above however I&#8217;d like to relax boundaries. Especially when doing exploratory programming and <code>part1</code>, <code>part2</code>, <code>partN</code> have several clauses and invocation points, maintaining “forwarding” argument lists can impair your flow.</p>
<p>Common Lisp has <a href="http://www.gigamonkeys.com/book/variables.html#dynamic-aka-special-variables">dynamic variables</a>.  They&#8217;re best described through an example (leaving out the parentheses, since they scare away large chunks of the population):</p>
<pre><code>
&gt; defvar *player* "Dr. Falken"
*PLAYER*

&gt; defun player-greeting
&gt;   concatenate 'string "Hello, " *player*
PLAYER-GREETING

&gt; player-greeting
"hello, Dr. Flaken"

&gt; let ((*player* "Matt")) player-greeting
"hello, Matt"

&gt; player-greeting
"hello, Dr. Flaken"
</code>
</pre>
<p><code>let</code> temporarily changes the binding of <code>*player*</code> for the scope <code>player-greeting</code> is evaluated in.</p>
<p>Here&#8217;s a way to do it in Erlang.  (Read it up to the end, there are caveats.)</p>
<p>First, user&#8217;s point of view:</p>
<pre><code>
player_greeting() -&gt;
    "Hello, " ++ dynvar:fetch(player).

test() -&gt;
    Greeting = dynvar:with([{player, "Dr. Falken"}],
                           fun player_greeting/0),
    Greeting.
</code>
</pre>
<p>Invoking test/0 will produce <code>"Hello, Dr. Falken"</code>.</p>
<p>The code:</p>
<pre><code>
-module(dynvar).
-export([with/2, fetch/1, test/0]).

with(Bindings, Action) -&gt;
    lists:foreach(fun({Name, Value}) -&gt; put(Name, Value) end, Bindings),
    try apply(Action, []) of
        X -&gt; X
    after
        lists:foreach(fun({Name, _Value}) -&gt; erase(Name) end, Bindings)
    end.

fetch(VarName) -&gt;
    get(VarName).
</code>
</pre>
<p>Yes, the process dictionary seems to be at the epicenter of  dirty Erlang hacks. <img src='http://hyperstruct.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>A few considerations:</p>
<ul>
<li>Common Lisp&#8217;s <code>player-greeting</code> can work without a “let” explicitly binding a value to <code>*player*</code>.  The Erlang example can&#8217;t.  This isn&#8217;t necessarily a drawback (see next point).</li>
<li>Syntax of the Erlang example is more verbose.  A few bytes could be shaved off using macros and ditching dynvar:fetch/1, but that would only be a win in the eyes of the “beauty above all” crowd (<em>surface</em> beauty, let me add).  First, indirecting via a macro would make life harder for whomever maintains the code six months down the road.  Second, when you&#8217;re going against the grain of the language, you may want the comments to mention it, and you really want the code to <em>scream</em> it.  (Do as I say, don&#8217;t do <a href="http://hyperstruct.net/2007/6/26/literal-xml-in-erlang-with-parse-transform-2">as I do</a>.)</li>
<li>This may collide with other uses of the process dictionary.  Consider adding a unique prefix to keys (e.g. <code>dynvar-</code>) before put()&#8217;ting them into the dictionary if that is an issue.</li>
<li>Where will you want to use this?  Well, I&#8217;m using it in the internals of the <a href="http://hyperstruct.net/projects/seethrough">seethrough template engine</a> to avoid passing arguments through intermediate layers.  Using it in library internals, preferably within a single module, not leaking signs of <code>dynvar</code> to the library user, is where I can advise to use this and still retain a clear conscience.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://hyperstruct.net/2008/01/31/dynamic-variables-hack-in-erlang/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Literal XML in Erlang with parse_transform/2</title>
		<link>http://hyperstruct.net/2007/06/26/literal-xml-in-erlang-with-parse-transform-2/</link>
		<comments>http://hyperstruct.net/2007/06/26/literal-xml-in-erlang-with-parse-transform-2/#comments</comments>
		<pubDate>Tue, 26 Jun 2007 06:00:00 +0000</pubDate>
		<dc:creator>bard</dc:creator>
				<category><![CDATA[Documentation]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[metaprogramming]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://hyperstruct.net/2007626literal-xml-in-erlang-with-parse-transform-2/</guid>
		<description><![CDATA[One of the things I dislike about Erlang is that it severely impairs bragging opportunities.  Yesterday I wrote a module that allows writing literal <span class="caps">XML</span> in the source and have it parsed into Erlang structures at compile timesort of like <a href="http://en.wikipedia.org/wiki/E4x"><span class="caps">E4X</span></a> minus the manipulation goodies at runtime (at least for now).


You write:


<pre><code>
Doc = '&#60;greeting&#62;Hello!&#60;/greeting&#62;',
io:format("~p~n", [Doc]).
</code>
</pre>

And it prints]]></description>
			<content:encoded><![CDATA[<p>One of the things I dislike about Erlang is that it severely impairs bragging opportunities.  Yesterday I wrote a module that allows writing literal <span class="caps">XML</span> in the source and have it parsed into Erlang structures at compile time—sort of like <a href="http://en.wikipedia.org/wiki/E4x"><span class="caps">E4X</span></a> minus the manipulation goodies at runtime (at least for now).</p>
<p>You write:</p>
<pre><code>
Doc = '&lt;greeting&gt;Hello!&lt;/greeting&gt;',
io:format("~p~n", [Doc]).
</code>
</pre>
<p>And it prints…</p>
<p><!--break--></p>
<pre><code>
{xmlElement,greeting,
            greeting,
            [],
            {xmlNamespace,[],[]},
            [],
            1,
            [],
            [{xmlText,[{greeting,1}],1,[],"Hello!",text}],
            [],
            "/tmp",
            undeclared}
</code>
</pre>
<p>In most languages I’m familiar with, this would have granted the author instant Yacc-demigod status.  With Erlang… it was less than <a href="http://repo.hyperstruct.net/inline_xml/inline_xml.erl">40 <span class="caps">LOC</span></a>.  Hardly something you’d wear at a party.</p>
<p>Anyway, this code owes everything to <a href="http://chlorophil.blogspot.com/2007/04/erlang-macro-processor-v2-part-i.html">Philip’s writings</a>. It also uses <code>parse_transform/2</code>, and <a href="http://www.erlang.org/doc/man/erl_id_trans.html">“programmers are strongly advised not to engage in parse transformations and no support is offered for problems encountered”</a>.  So unless you, like me, are still at the kid-in-a-candy-shop stage of Erlang experience, think twice before using this in production, ok?</p>
<p>The code is <a href="http://repo.hyperstruct.net/inline_xml/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://hyperstruct.net/2007/06/26/literal-xml-in-erlang-with-parse-transform-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Installing the StartCom SSL certificate in ejabberd</title>
		<link>http://hyperstruct.net/2007/06/20/installing-the-startcom-ssl-certificate-in-ejabberd/</link>
		<comments>http://hyperstruct.net/2007/06/20/installing-the-startcom-ssl-certificate-in-ejabberd/#comments</comments>
		<pubDate>Wed, 20 Jun 2007 06:00:00 +0000</pubDate>
		<dc:creator>bard</dc:creator>
				<category><![CDATA[Documentation]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Jabber]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[ejabberd]]></category>
		<category><![CDATA[ssl]]></category>
		<category><![CDATA[startcom]]></category>

		<guid isPermaLink="false">http://hyperstruct.net/2007620installing-the-startcom-ssl-certificate-in-ejabberd/</guid>
		<description><![CDATA[The <a href="http://www.xmpp.org">XMPP Software Foundation</a> <a href="http://www.xmpp.org/xsf/press/2006-12-06.shtml">established</a> an intermediate certification authority with <a href="http://www.startcom.org">StartCom</a>.  If you run a public federated XMPP server, in order to provide secure communication, you no longer need to buy an SSL certificate (or resort to a self-signed certificate): simply register an account at <a href="http://www.xmpp.net">http://www.xmpp.net</a> and follow the <a href="https://www.xmpp.net/certificate-process">certificate request process</a]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.xmpp.org">XMPP Software Foundation</a> <a href="http://www.xmpp.org/xsf/press/2006-12-06.shtml">established</a> an intermediate certification authority with <a href="http://www.startcom.org">StartCom</a>.  If you run a public federated XMPP server, in order to provide secure communication, you no longer need to buy an SSL certificate (or resort to a self-signed certificate): simply register an account at <a href="http://www.xmpp.net">http://www.xmpp.net</a> and follow the <a href="https://www.xmpp.net/certificate-process">certificate request process</a>.</p>
<p><!--break--></p>
<p>At least up to ejabberd <del>1.1.2</del> 1.1.4, however, there is an extra step which involves patching a file and recompiling. (<strong>Update</strong>: the patching step is no longer required in ejabberd 2.0.0.)</p>
<p>Here is the complete procedure I followed.</p>
<p>After the certificate request process, you should have these files:</p>
<ul>
<li>ssl.key (resulting from the certificate request process)</li>
<li>ssl.crt (idem)</li>
<li>ca.crt (<a href="http://cert.startcom.org/ca.crt">available from StartCom</a>)</li>
<li>sub.class1.xmpp.ca.crt (<a href="http://cert.startcom.org/sub.class1.xmpp.ca.crt">available from StartCom</a>)</li>
</ul>
<p>Decode ssl.key.  openssl will ask you for a password, provide the one you gave during the certificate request process:</p>
<pre><code>
$ openssl rsa -in ssl.key -out ssl.key
</code>
</pre>
<p>Concatenate your server’s certificate plus key and the intermediate certificate into a single file:</p>
<pre><code>
cat ssl.crt ssl.key sub.class1.xmpp.ca.crt &gt;ejabberd.pem

</code>
</pre>
<p>Place the resulting file where the ejabberd server is able to access it.</p>
<p>On Debian:</p>
<pre><code>
chown ejabberd.ejabberd ejabberd.pem
chmod 400 ejabberd.pem
mv ejabberd.pem /etc/ejabberd
</code>
</pre>
<p>Configure ejabberd.cfg:</p>
<pre><code>
% Ordinary client-2-server service
 [{5222, ejabberd_c2s,     [{access, c2s},
                            {max_stanza_size, 65536},
                            starttls, {certfile, "/etc/ejabberd/ejabberd.pem"},
                            {shaper, c2s_shaper}]},

% SSL-enabled client-2-server service
  {5223, ejabberd_c2s,     [{access, c2s},
                            {max_stanza_size, 65536},
                            tls, {certfile, "/etc/ejabberd/ejabberd.pem"},
                            {shaper, c2s_shaper}]},

% [...]

% Use STARTTLS+Dialback for S2S connections
{s2s_use_starttls, true}.
{s2s_certfile, "/etc/ejabberd/ejabberd.pem"}.
</code>
</pre>
<p>Restart the server.</p>
<p>At this point, the certificate is installed but ejabberd <a href="http://lists.jabber.ru/pipermail/ejabberd/2006-December/002368.html">is not presenting it correctly</a>. If you run the following:</p>
<pre><code>
openssl s_client -connect your.server.org:5223 -CAfile /path/to/ca.crt
</code>
</pre>
<p>You will get an incomplete certificate chain:</p>
<pre><code>
[...]
verify error:num=21:unable to verify the first certificate
verify return:1
CONNECTED(00000003)
---
Certificate chain
 0 s:/C=US/ST=Your State/L=Your Location/O=Your Name/OU=Domain validated only/CN=your@server.org/emailAddress=hostmaster@server.org
   i:/C=US/ST=Colorado/O=Jabber Software Foundation/OU=Secure Certificate Signing/CN=StartCom Class 1 Intermediate CA - Jabber Software Foundation/emailAddress=certmaster@jabber.org
---
Server certificate
-----BEGIN CERTIFICATE-----
[...]
</code>
</pre>
<p>To fix it, you have to apply a small patch.  Start by downloading ejabberd source.</p>
<p>On Debian:</p>
<pre><code>
apt-get source ejabberd
</code>
</pre>
<p>Now you could grab <a href="https://support.process-one.net/secure/attachment/10961/ejabberd-certificate-chain.patch">the patch</a> from the <a href="https://support.process-one.net/browse/EJAB-209">ejabberd bug tracker</a> and use the “patch” tool to apply it, however as of ejabberd 1.1.2 line numbers have shifted and it won’t apply cleanly.  Since it’s a one-liner, just open the file src/tls/tls_drv.c and locate the following line:</p>
<pre><code>
res = SSL_CTX_use_certificate_file(d-&gt;ctx, buf, SSL_FILETYPE_PEM);
</code>
</pre>
<p>Replace it with the following:</p>
<pre><code>
res = SSL_CTX_use_certificate_chain_file(d-&gt;ctx, buf);
</code>
</pre>
<p>To compile it, either go to the src/ directory and type:</p>
<pre><code>
make
</code>
</pre>
<p>Or, on Debian, generate a new package:</p>
<pre><code>
fakeroot dpkg-buildpackage -uc -nc
</code>
</pre>
<p>Reinstall, and you’re done.</p>
<p>To verify that it’s working, run again:</p>
<pre><code>
$ openssl s_client -connect sameplace.cc:5223 -CAfile /path/to/ca.crt
</code>
</pre>
<p>This time you should get:</p>
<pre><code>
[...]
verify return:1
CONNECTED(00000003)
---
Certificate chain
 0 s:/C=US/ST=Your State/L=Your Location/O=Your Name/OU=Domain validated only/CN=your@server.org/emailAddress=hostmaster@server.org
   i:/C=US/ST=Colorado/O=Jabber Software Foundation/OU=Secure Certificate Signing/CN=StartCom Class 1 Intermediate CA - Jabber Software Foundation/emailAddress=certmaster@jabber.org
 1 s:/C=US/ST=Colorado/O=Jabber Software Foundation/OU=Secure Certificate Signing/CN=StartCom Class 1 Intermediate CA - Jabber Software Foundation/emailAddress=certmaster@jabber.org
   i:/C=IL/ST=Israel/L=Eilat/O=StartCom Ltd./OU=CA Authority Dep./CN=Free SSL Certification Authority/emailAddress=admin@startcom.org
---
Server certificate
-----BEGIN CERTIFICATE-----
[...]
</code>
</pre>
<p>Which is a complete certificate chain and openssl is able to verify it against the root certificate.</p>
]]></content:encoded>
			<wfw:commentRss>http://hyperstruct.net/2007/06/20/installing-the-startcom-ssl-certificate-in-ejabberd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>seethrough 0.1: sub-templates, and cache-ready</title>
		<link>http://hyperstruct.net/2007/02/13/seethrough-0-1-sub-templates-and-cache-ready/</link>
		<comments>http://hyperstruct.net/2007/02/13/seethrough-0-1-sub-templates-and-cache-ready/#comments</comments>
		<pubDate>Tue, 13 Feb 2007 07:00:00 +0000</pubDate>
		<dc:creator>bard</dc:creator>
				<category><![CDATA[Documentation]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Releases]]></category>
		<category><![CDATA[metaprogramming]]></category>
		<category><![CDATA[templating]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://hyperstruct.net/2007213seethrough-0-1-sub-templates-and-cache-ready/</guid>
		<description><![CDATA[<p>Uh oh.  Beware when you take an evening&#8217;s hack and put it online, as
someone who knows what he&#8217;s doing might come along and turn it into
something useful.</p>


	<p>That happened to
<a href="http://blog.hyperstruct.net/2007/1/7/seethrough-a-simple-xml-xhtml-templating-system-for-erlang">seethrough</a>, with a patch courtesy of <a href="http://wagerlabs.com/">Joel</a>, who added two major features:</p]]></description>
			<content:encoded><![CDATA[<p>Uh oh.  Beware when you take an evening’s hack and put it online, as someone who knows what he’s doing might come along and turn it into something useful.</p>
<p>That happened to <a href="http://blog.hyperstruct.net/2007/1/7/seethrough-a-simple-xml-xhtml-templating-system-for-erlang">seethrough</a>, with a patch courtesy of <a href="http://wagerlabs.com/">Joel</a>, who added two major features:</p>
<ul>
<li>sub-template inclusion, via the <code>&lt;e:include/&gt;</code> tag;</li>
<li>parse/render stage split.</li>
</ul>
<p>The latter means that the (possibly expensive) parse and preparation stage only needs to be performed once.  The resulting intermediate form can be cached, and rendered many times within different environments.  For example:</p>
<pre><code>
%% Parsing
{XMLTree, _Misc} = xmerl_scan:file(File),
Intermediate = seethrough:visit(XMLTree),

%% Rendering intermediate form within Env1
Render1 = seethrough:render(Intermediate, Env1),
xmerl:export_simple(lists:flatten([Render1]), xmerl_xml,
                    [#xmlAttribute{name = prolog, value = ""}]).

%% More rendering, but within Env2
Render2 = seethrough:render(Intermediate, Env2),
xmerl:export_simple(lists:flatten([Render2]), xmerl_xml,
                    [#xmlAttribute{name = prolog, value = ""}]).

%% Yet more rendering, within Env3
Render3 = seethrough:render(Intermediate, Env3),
xmerl:export_simple(lists:flatten([Render3]), xmerl_xml,
                    [#xmlAttribute{name = prolog, value = ""}]).

</code>
</pre>
<p>Kudos to Joel!</p>
]]></content:encoded>
			<wfw:commentRss>http://hyperstruct.net/2007/02/13/seethrough-0-1-sub-templates-and-cache-ready/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>seethrough: a simple XML/XHTML templating system for Erlang</title>
		<link>http://hyperstruct.net/2007/01/07/seethrough-a-simple-xml-xhtml-templating-system-for-erlang/</link>
		<comments>http://hyperstruct.net/2007/01/07/seethrough-a-simple-xml-xhtml-templating-system-for-erlang/#comments</comments>
		<pubDate>Sun, 07 Jan 2007 07:00:00 +0000</pubDate>
		<dc:creator>bard</dc:creator>
				<category><![CDATA[Documentation]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[metaprogramming]]></category>
		<category><![CDATA[templating]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://hyperstruct.net/200717seethrough-a-simple-xml-xhtml-templating-system-for-erlang/</guid>
		<description><![CDATA[Speaking of winter evenings, a couple of weeks ago over Christmas I spent a few hours whipping together a simple templating system for Erlang.

Today I took another couple of hours to put it under version control and to add some ideas I found in <a href="http://www.zope.org/Documentation/ZopeBook/ZPT.stx"><span class="caps">ZPT</span></a>, a similar system (hat tip to <a href="http://sautret.org">Jérôme</a> for pointing it out).
]]></description>
			<content:encoded><![CDATA[<p>Speaking of winter evenings, a couple of weeks ago over Christmas I spent a few hours whipping together a simple templating system for Erlang.</p>
<p>Today I took another couple of hours to put it under version control and to add some ideas I found in <a href="http://www.zope.org/Documentation/ZopeBook/ZPT.stx"><span class="caps">ZPT</span></a>, a similar system (hat tip to <a href="http://sautret.org">Jérôme</a> for pointing it out).</p>
<p>This is how it works: you start with an <span class="caps">XHTML</span> (or any <span class="caps">XML</span>) file with some extra attributes thrown in and properly namespaced:</p>
<pre><code>
&lt;html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:e="http://dev.hyperstruct.net/seethrough"&gt;
  &lt;head&gt;
    &lt;title e:content="title"/&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1 e:content="title"/&gt;

    &lt;h2&gt;&lt;span e:replace="subtitle"/&gt;&lt;/h2&gt;

    &lt;table&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;Address&lt;/th&gt;
          &lt;th&gt;Name&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr e:repeat="crew"&gt;
          &lt;td e:content="address"/&gt;
          &lt;td e:content="name"/&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/body&gt;
&lt;/html&gt;

</code></pre>
<p>Since it is a valid document, even designers can load it into their <span class="caps">WYSIWYG</span> editors and be happy.</p>
<p>Next, you pass the file name along with an <em>environment</em> (a list of key/value tuples) to <code>apply_template/2</code>:</p>
<pre><code>
seethrough:apply_template("test.html",
    [{title, "Space"},
     {subtitle, {mymod, get_subtitle, []}},
     {crew, {mymod, get_crew, []}}])).

</code></pre>
<p>Given such input and such environment:</p>
<ul>
<li><code>&lt;h1 e:content="title"/&gt;</code> will be replaced by <code>&lt;h1&gt;Space&lt;/h1&gt;</code>.</li>
<li><code>&lt;span e:replace="subtitel"/&gt;</code> will be replaced by the result of <code>mymod:get_subtitle/0</code>.</li>
<li><code>&lt;tr e:repeat="crew"&gt;...&lt;/tr&gt;</code> will be repeated as many times as there are elements in the (list-)result of <code>mymod:get_crew/0</code>.</li>
</ul>
<p>Here is the output:</p>
<pre><code>
&lt;?xml version="1.0"?&gt;
&lt;html xmlns:e="http://dev.hyperstruct.net/seethrough"
      xmlns="http://www.w3.org/1999/xhtml"&gt;
  &lt;head&gt;
    &lt;title&gt;Space&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;Space&lt;/h1&gt;

    &lt;h2&gt;The last frontier...&lt;/h2&gt;

    &lt;table&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;Address&lt;/th&gt;
          &lt;th&gt;Name&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;td&gt;kirk@enterprise.glx&lt;/td&gt;
          &lt;td&gt;Jim&lt;/td&gt;
        &lt;/tr&gt;&lt;tr&gt;
          &lt;td&gt;spock@enterprise.glx&lt;/td&gt;
          &lt;td&gt;Spock&lt;/td&gt;
        &lt;/tr&gt;&lt;tr&gt;
          &lt;td&gt;mccoy@enterprise.glx&lt;/td&gt;
          &lt;td&gt;Doc&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/body&gt;
&lt;/html&gt;

</code></pre>
<p>Only a tiny part of <span class="caps">ZPT</span> (basically, what is needed in the above example) is mirrored so far. While I will bring more of it in, since it is obviously well designed, this will not be a port, partly because Erlang is not Python and there might be other good design choices around the corner, partly because I spent some time generating <span class="caps">XHTML</span> in Erlang the usual way (<code>{body, [], [{p, [], [...]}], gen_table(...)}</code>) and while it might not be the most familiar thing in the world, dealing with <span class="caps">XML</span> generation as function composition is fascinating and it would be nice to bring <em>that</em> into the picture.</p>
<p>The code is available at <a href="http://repo.hyperstruct.net/seethrough">http://repo.hyperstruct.net/seethrough</a>.</p>
<p><strong>Update 13/01</strong>: <a href="http://www.divmod.org/users/mg/nevow-doc/nevow-xml-templates.html">Nevow <span class="caps">XML</span> Templates</a> provide more excellent inspiration.</p>
<p><strong>Update 17/01</strong>: The <code>&lt;attr&gt;</code> tag á  la Nevow has been added (it affects attributes of the parent element).  A project page is also available at <a href="http://hyperstruct.net/projects/seethrough">http://hyperstruct.net/projects/seethrough</a>, please see that for an updated example of template processing.</p>
<p><strong>Update 13/02</strong>: Now with <a href="http://hyperstruct.net/2007/2/13/seethrough-0-1-sub-templates-and-cache-ready/">sub-templates and cache-ready</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://hyperstruct.net/2007/01/07/seethrough-a-simple-xml-xhtml-templating-system-for-erlang/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

