📜 ⬆️ ⬇️

Universal template engine for 1 minute from scrap materials

Template

It's no secret for anyone now that the template engine should be a full-fledged programming language.

Do not forget that the use of templates is far from being limited to WEB.
These include the generation of various types of reports, the generation of code for programs in various languages, the generation of source data for processing, and much more.
In general, I want to apply templates everywhere where there is a lot of text and a little logic.
')
In thought, how to do it quickly and cheaply, you should not deceive yourself (mostly at an early stage) with thoughts like “yes I have a static text, just need to glue the cap”, “only the counter is needed”, “I need only to withdraw date "etc.
First, the header and the counter, then there will be a conditional block insertion (if), then you will need to generate tables (we need cycles and arrays), then string operations and all other constructions of the normal programming language will be pulled.

Search for a solution


Since I was not going to invent my own programming language, but I wanted a solution quickly and cheaply, I took perl for the beginning with its regexps and started generating output by tags of the form <?=value?> And <? code ?> <? code ?> .
The code turned out a type
 print "text";print $value; code 

On the other hand, after seeing how double quotes are inserted, I realized that I was doing what was already done before me: the perl compiler itself replaces strings when parsing text
 "abc $var cde" 
on
 "abc ".$var." cde" 

Well and fine, it is possible to insert values ​​and through $ var, and to receive result eval th.
This is already half the battle: we can already insert variables and array elements into the template.
It remains to decide what to do with the code.

Here interpolation of arrays comes to the rescue:
 print "5*5 = @{[5*5]}" 
will lead
5*5 = 25

Perhaps this hack requires explanation.
With interpolation, @ means that we will now output an array. Further, {} separates the array itself from the surrounding text, and [] indicates that we will insert the array by reference.
However, we already generate the contents of the array with the code that is substituted there. And this must be remembered in the future: everything that we do here in the quadrant brackets is the context of the array.

That is, the mechanism of work: creating an array (often with one element), creating a link to it and then outputting this array by reference. Not optimal, for that - it works.

So, we can also insert the code into the string.
A little more - and ...

Decision


 #!/usr/bin/perl -w use strict; { local $/ = undef; $txt = <>; } print eval qq{<< "__END_OF_TEMPLATE"\n$txt\n__END_OF_TEMPLATE\n}; die $@ if $@; 

Everything.
This is the template engine.
If desired, it even fits on a single line in perl -e.

What is it and why


This is really the shortest and easiest template engine I've ever seen. You can run it wherever there is perl and you don’t need to download, build, install anything - in some cases this is quite a big problem.

There is a substitution of values ​​through $, code execution on perl through @ {[]}, there is a correct error output with the correct indication of the line number. There is even modularity here: important, frequently used and long functions are separated into a separate module or just a source code, which is then connected from the template itself via use or do, respectively.
Practically doing nothing, we got almost everything we need!

Templates have the following form:
!
: @{[''.localtime]}.
PID: $$
\@INC path: @INC
Environment:
@{[join "\n", map {".... $_ => $ENV{$_}"} sort keys %ENV]}
@{[do{use IO::File; IO::File->new("<tail.inc")->getlines()}]}

Almost unchanged, I used it in several tasks:
• in a specific samopinny http-server pages were contained in hash (along the way) and the result was calculated and given to the client through the same mechanism;
• generated C ++ code with complex structures and dependencies, the data were described in a deep branched perl structure - there was an XSLT equivalent on hashes and arrays;
• made a substitute for autotools to generate a Makefile.
Not to mention the many small applications.
The universality here consists in the fact that nowhere is there at all any binding to the generated content, and specific functions can be done for any application.

In general, if you have nothing and you urgently need to substitute something in the template, this method is for you.

If you want to receive code from clients, you can look in the direction of such modules as Safe or ops , but at once I want to say that I don’t offer a complete solution here.

Where to use it is not necessary:
• Do not try to give this to designers and do not need them to require templates in this format. Remember that this is actually a PERL program, albeit looking like HTML (or something else).
• Without serious improvement, you should not directly push content from users there, most likely this will lead to local code execution and hacking.
• Binary data can be generated, but at least we need to think about what to do with the last line feed (probably, just tear it off).
• If you already have the “correct” template engine, customized for your task, you also do not need this crutch.

In areas where this method of templating has been used by me, the method has proved to be excellent and in some places it still works.

I will answer all questions if they arise.

Source: https://habr.com/ru/post/115173/


All Articles