EEl - Embedded Erlang - template renderer (WIP)

Ok, I’m here again after a while to talk about this lib called EEl.
Just merged a new code, I rewrote everything from scratch.
The idea is the same, but now it’s more simple and more versatile.
There is now the possibility to define a custom engine using the eel_engine behavior. The default one is the eel_smart_engine. The job of the engine is to convert the code into AST (Abstract Syntax Tree).

Compare the eel_smart_engine implementation to a simple engine used for tests.

See the README for more details, but in a nutshell, strings and files can be compiled and evaluated to binary. For example, using a simple binary as the template:

1> eel:eval(<<"Hello, <%= Name .%>!">>, #{'Name' => <<"World">>}).
[<<"Hello, ">>,<<"World">>,<<"!">>]

or compiling it to a module

1> eel:compile_to_module(<<"Hello, <%= Name .%>!">>, foo).
{ok,foo}
2> foo:eval(#{'Name' => <<"World">>}).
[<<"Hello, ">>,<<"World">>,<<"!">>]

or using the eel module functions.

Taking the module example, the is a render function that gives this result:

3> foo:render(#{'Name' => <<"World">>}).
{[<<"Hello, ">>,<<"World">>,<<"!">>],
 #{ast =>
       [{2,
         {{1,8},
          [{call,1,
               {remote,1,{atom,1,eel_converter},{atom,1,to_binary}},
               [{'fun',1,
                    {clauses,[{clause,1,[],[],[{var,1,'Name'}]}]}}]}]}}],
   bindings => #{'Name' => <<"World">>},
   changes => [{2,<<"World">>}],
   dynamic => [{2,{{1,8},<<"World">>}}],
   static => [{1,{{1,1},<<"Hello, ">>}},{3,{{1,20},<<"!">>}}],
   vars => [{2,['Name']}]}}

It returns a tuple with the binary and a metadata that I called snapshot. See for what the snapshot is useful by looking at the example in the docs, but basically, it holds information to prevent the need to recompile and gives the information to only evaluate what changed.

Note about the key of the bindings/variables passed to render/eval. Is totally fine to write keys in snake_case like #{name => <<"World">>} instead of #{'Name' => <<"World">>}, or better, #{ThisIsFine => ok} can be write as #{this_is_fine => ok}.

From time to time I see people asking about Erlang for Web Development or what framework to use. I believe this lib can help in some manner.

Just a side note writing the template directly in an Erlang module, e.g.

foo() ->
    eel:compile(<<\"
        You need to \"escape\" all \"quoted texts\" inside this binary.
        Also, you will have some indentation issues.
    \">>).

This recent proposal can help to write better multi-line texts.

Disclaimer: It is still a WIP. There are few docs, specs and tests.

And that’s it.
Suggestions welcome.

All the best,
William

6 Likes