B2.Usage Example
B2.Usage Example
The translation of the Meepo template does NOT depend on any other template. Pebble
is here for testing and demo only, as its benchmark and syntax are better.
Templates like Pebble
, FreeMarker
, and Velocity
have their own syntax and are widely used in web services. Some IDEs have plug-in support, but it's all for the template language, not the target file language, including syntax highlighting, autocompelet.
The Thymeleaf
(recently discontinued) templates do not break the target file syntax and the application area is bound to specific language features.
The intention of Meepo is NOT the dynamic capabilities of the template, but the execution engines
(such as js and java) can do very complex functional operations.
Although its performance is better than Freemarker
, Velocity
and 3 times better than thymeleaf
in the jmh
benchmark. It is not recommended to use Meepo for engineering view layer rendering, it is suitable for template middle layer, or called template translator.
Because markdown has its own understanding of spaces and empty lines, please see the source code in the link for precise identification of spaces and empty lines.
B2.1.Ignore Blank in Directive, Readability First
The underlying template blog-trim.peb cannot be handled effectively in html
and js
syntax, although the IDE plugin is able to recognize pebble
syntax.
<body>
{% for article in articles %}
<h3>{{ article.title }}</h3>
<p>{{ article.content }}</p>
{% endfor %}
<script type="text/javascript">
var machineId = {{machineId}}
</script>
</body>
The same output blog-trim.htm, which retains the original html and js features, can be edited as html. It can also be edited with the pebble plugin.
Without using !
, if the directive takes the entire line and other chars in the line are all whitespace, then that line will not be printed. The first line has a space for testing purposes.
<!-- HI-MEEPO -->
<body>
<!-- DNA:RAW {% for article in articles %} -->
<h3>{{ article.title }}</h3>
<p>{{ article.content }}</p>
<!-- DNA:RAW {% endfor %} -->
<script type="text/javascript">
// HI-MEEPO
// DNA:SET /"machine-id"/{{machineId}}/
var machineId = "machine-id"
</script>
</body>
B2.2.Keep Blank in Directive, Consistency First
The underlying template blog-pure.peb, Note that there is a blank line before <body>
and a total of 4x3=12 spaces before var
.
<body>
{% for article in articles %}
<h3>{{ article.title }}</h3>
<p>{{ article.content }}</p>
{% endfor %}
<script type="text/javascript">
var machineId = {{machineId}}
</script>
</body>
The use of !
makes Meepo handle only the content between the beginning and the end of the comment, leaving out newlines and whitespace (4 spaces each for the first 2 lines of var).
<!-- HI-MEEPO! -->
<body>
<!-- DNA:RAW {% for article in articles %} -->
<h3>{{ article.title }}</h3>
<p>{{ article.content }}</p>
<!-- DNA:RAW {% endfor %} -->
<script type="text/javascript">
// HI-MEEPO!
// DNA:SET /"machine-id"/{{machineId}}/
var machineId = "machine-id"
</script>
</body>
B2.3.Replace All with Anonymous Global
Output results of replace-all-o.htm
<div>
use anonymous all-life to replace div to div
</div>
Meepo template for replace-all-i.htm, using *
for anonymous global replacement.
<!-- HI-MEEPO -->
<!-- DNA:SET /body/div/* -->
<body>
use anonymous all-life to replace body to div
</body>
B2.4.Replace Interval with Specified Range
Output results of replace-1a3-o.htm
<div>
use ranged-life to replace 1st and 3rd body to div
</div>
Meepo template for replace-1a3-i.htm, using 1,3
comma-separated number confirmation.
<!-- HI-MEEPO -->
<!-- DNA:SET /body/div/1,3 -->
<body>
use ranged-life to replace 1st and 3rd body to div
</body>
B2.5.Replace Range with Named Global
Output results of replace-end-o.htm
<body>
use named-life to replace scoped div to div
</body>
Meepo template for replace-end-i.htm, using end
and named lifecircle.
<!-- HI-MEEPO -->
<body>
<!-- DNA:SET /body/div/body -->
use named-life to replace scoped body to div
<!-- DNA:END body -->
</body>
B2.6.Keeping the Original, Magic Immunity BKB
Output results of black-king-bar-o.htm
<!-- DNA:SET /body/div/* -->
<body>
in bkb, all are plain text, including DNA:SET
</body>
Meepo template for black-king-bar-i.htm, using end
and named lifecircle.
<!-- HI-MEEPO -->
<!-- DNA:BKB bkb -->
<!-- DNA:SET /body/div/* -->
<body>
in bkb, all are plain text, including DNA:SET
</body>
<!-- DNA:END bkb -->
B2.7.Delete Line/Block, actually replace with Empty
Output results of delete-1a3-o.htm
delete all, but this line
Meepo template for delete-1a3-i.htm, Delete (replace with empty) the 1st and 3rd matching lines.
<!-- HI-MEEPO -->
<!-- DNA:SET /^.*\n?//1,3 -->
<body>
delete all, but this line
</body>
Meepo template for delete-all-i.htm, Delete body and all while.
<!-- HI-MEEPO -->
<!-- DNA:SET :<body>[\s\S]*</body>:: -->
<body>
delete all, but this line
</body>
B2.8.Execute Once, Stored in Model
Output results of put-use-o.htm
<body>
1009+10+7=1026
1009+10+7=1026
</body>
Meepo template for put-use-i.htm, single execution with PUT
and USE
everywhere.
<!-- HI-MEEPO -->
<!-- RNA:PUT js/calc/1009+10+7/ -->
<body>
<!-- RNA:USE /result/calc/* -->
1009+10+7=result
1009+10+7=result
</body>
B2.9.Execute Every Time, JS Counter
Output results of run-any-o.htm
<body>
i=1009+10+7=1026
i++ == 1027
i++ == 1028
</body>
Meepo template for run-any-i.htm, using RUN and js execution engine.
<!-- HI-MEEPO -->
<!-- RNA:RUN js//i=1009+10+7/ -->
<!-- RNA:RUN js/counter/i++;i.toFixed()/* -->
<body>
i=1009+10+7=1026
i++ == counter
i++ == counter
</body>
B2.A.Import Static Text at Runtime
Use the uri
engine to read external resources such as file://
, classpath:
and http://
.
Output results of import-o.htm
imported text
Meepo template for import-i.htm, read import-f.htm
<!-- HI-MEEPO -->
<!-- RNA:RUN uri#import-here#classpath:/template/imp/import-f.htm# -->
import-here
B2.B.Execute java Code, Compile Dynamically
Output results of compile-java-o.htm
2020-07-09 00:00:00
Meepo template for compile-java-i.htm
<!-- HI-MEEPO -->
<!-- RNA:RUN java#java-output#
import java.time.LocalTime, java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
LocalDate date = LocalDate.parse("2020-07-09");
LocalDateTime ldt = LocalDateTime.of(date, LocalTime.of(0, 0, 0));
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return ldt.format(fmt);
# -->
java-output
B2.C.Customize Delimiter Instead of Slash
The delimiter
is the 1st non-(blank
, !
, alphanum
) 1-2 byte char, commonly used as /
, unicode characters, just avoid repeating it in the content, however, 3,4 byte chars like 👹 are not allowed, getChar
will not work correctly.
// RNA:RUN js/counter/i++;i.toFixed()/
// RNA:RUN js:counter:i++;i.toFixed():
// RNA:RUN js|counter|i++;i.toFixed()|
// RNA:RUN js汉counter汉i++;i.toFixed()汉
B2.D.Auto-Indent Multi Lines, Nice and Easy
In the test JavaTest.java, variable
is a collection, its elements come with newlines.
c.put("method", Arrays.asList("LocalDate date = LocalDate.parse(\"2020-07-09\");\n",
"LocalDateTime ldt = LocalDateTime.of(date, LocalTime.of(0, 0, 0));\n",
"DateTimeFormatter fmt = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\");\n",
"return ldt.format(fmt);"));
will output with indented JavaOut.java
public Object eval(@NotNull Map<String, Object> ctx) {
LocalDate date = LocalDate.parse("2020-07-09");
LocalDateTime ldt = LocalDateTime.of(date, LocalTime.of(0, 0, 0));
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return ldt.format(fmt);
}
If the variable
is a string with \n
instead of a collection, the effect will be like this,
public Object eval(@NotNull Map<String, Object> ctx) {
LocalDate date = LocalDate.parse("2020-07-09");
LocalDateTime ldt = LocalDateTime.of(date, LocalTime.of(0, 0, 0));
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return ldt.format(fmt);
}
B2.E.How to Customize Function
/* HI-MEEPO */
/* RNA:PUT fun/fun:abs/return Math.abs(((Number)obj).intValue())/ */
/* RNA:USE /abs/number|fun:abs/*/
abs
The above template, using RNA:PUT
and fun
engine puts a function
named fun:abs
into the context. When merging, context.put("number",-1), the template output is 1
, see testFunAbs
for details.
Map<String, Object> ctx=new HashMap<>();
Function<Number, Integer> abs=number->Math.abs(number.intValue());
ctx.put("fun:abs",abs);
ctx.put("number",-1);
// rna:use /now/number|abs/
The above is the runtime java code to do the same thing, see more,
- pipelined function, chain processing
- dynamic java function
fun
B2.F.Placeholder Template
No need to use the whole Meepo template, just handle template variable replacement and function call, the following 2 lines are input and output respectively.
Where {{moilion-circle|PascalCase}}
is, the template defined variable and function substitution.
"this is {{moilion-circle|PascalCase}} simple template"
"this is MoilionCircle simple template"
B2.G.Widget Features
Widget is a combination of View and Model, PUT
inside SON
is a component.
For example, the TopHead of a website usually loads the Model according to the id, and the template engine renders the View to get the output output.
The template engine supports the include function, but will not load the Model, because V and M should not be supported if their responsibilities are different.
In practice, we would prefer to have the Model loaded when the TopHead is included in the View layer. Not the View layer include once, and the Controller layer include again to load Model data.
Meepo has the ability to change the context at runtime, i.e., it can load the Model itself and turn it into a component. In the context of this article, import is the dynamic RNA category and include is the static DNA category.
Import sub-template with relative path include-i2.htm
<!-- HI-MEEPO -->
<!-- DNA:SON ./include-f.txt -->
since 2020-02-02
The content of sub-template include-f.txt
# HI-MEEPO
# DNA:SET /name/trydofor/
# RNA:USE /domain/gmail/
author = name@domain
Meepo template for include-o.htm
author = trydofor@gmail.com
since 2020-02-02