Skip to main content

B2.Usage Example

trydoforOriginalMeepoTemplateAbout 6 min

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.pebopen in new window 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.htmopen in new window, 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.pebopen in new window, 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.htmopen in new window

<div>
use anonymous all-life to replace div to div
</div>

Meepo template for replace-all-i.htmopen in new window, 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.htmopen in new window

<div>
use ranged-life to replace 1st and 3rd body to div
</div>

Meepo template for replace-1a3-i.htmopen in new window, 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.htmopen in new window

<body>
use named-life to replace scoped div to div
</body>

Meepo template for replace-end-i.htmopen in new window, 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.htmopen in new window

<!-- DNA:SET /body/div/* -->
<body>
in bkb, all are plain text, including DNA:SET
</body>

Meepo template for black-king-bar-i.htmopen in new window, 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.htmopen in new window

delete all, but this line

Meepo template for delete-1a3-i.htmopen in new window, 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.htmopen in new window, 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.htmopen in new window


<body>
1009+10+7=1026
1009+10+7=1026
</body>

Meepo template for put-use-i.htmopen in new window, 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.htmopen in new window


<body>
i=1009+10+7=1026
i++ == 1027
i++ == 1028
</body>

Meepo template for run-any-i.htmopen in new window, 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.htmopen in new window

imported text

Meepo template for import-i.htmopen in new window, read import-f.htmopen in new window

<!-- 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.htmopen in new window

2020-07-09 00:00:00

Meepo template for compile-java-i.htmopen in new window

<!-- 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.javaopen in new window, 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.javaopen in new window

    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.htmopen in new window

<!-- HI-MEEPO -->
<!-- DNA:SON ./include-f.txt -->
since 2020-02-02

The content of sub-template include-f.txtopen in new window

# HI-MEEPO
# DNA:SET /name/trydofor/
# RNA:USE /domain/gmail/
author = name@domain

Meepo template for include-o.htmopen in new window

author = trydofor@gmail.com

since 2020-02-02