2. Putting values in
What this is for
A page about nothing is a document. A page about your order needs values from somewhere.
In BMX the blank is called a slot, and it looks like this:
Dear {{ customer.name }},
Your total is {{ order.total }}.
Bind customer.name to Ada Lovelace and order.total to $59.97, and out comes:
<article class="bmx"><p>Dear Ada Lovelace,</p><p>Your total is $59.97.</p></article>
Think of a form letter
You have seen the paper version: “Dear __, your account ____ is now ______.” Somebody fills in the blanks and posts it.
Everybody has also received the version where it went wrong:
Dear ,
Your order is ready for collection.
Nobody typed that. A blank did not get filled and the machine printed it anyway, because an empty string is a perfectly good string and nothing was watching.
That is the interesting question about slots, and it is not “how do I put a value in”. It is what happens when the value is not there.
BMX refuses
Dear {{ customer.nmae }},
A typo — nmae. Here is what happens:
BMX-R002: no binding for slot `customer.nmae` at 8
An error. Not an empty string. The page does not render, so the page cannot ship saying “Dear ,”.
Compare that with what almost every other template language does with the same typo:
| Result | |
|---|---|
| Handlebars | renders nothing, page ships |
| Jinja2 (default) | renders nothing, page ships |
| Mustache | renders nothing, page ships |
| ERB | raises — but only if the object is nil in the wrong way |
| BMX | refuses; nothing renders |
The at 8 is a byte offset — character 8 of your file, which is where customer.nmae starts. Your
editor can jump there.
The value is always escaped
Say the customer’s name is, for whatever reason:
<script>alert('hi')</script>
You do not have to think about that. The value comes out as characters, not markup:
<p>Dear <script>alert('hi')</script>,</p>
There is no way to turn this off from inside a document. There is no {{{ raw }}} and there never
will be — three characters is too little to stand between a correct page and a compromised one. If
a host genuinely needs to emit trusted markup, it does that in its own code, on a line somebody can
find.
What goes inside the braces
BMX does not know. It reads the text between {{ and }}, trims the spaces, checks it is not
empty, and hands it to whatever is rendering the document.
So in a simple renderer, {{ order.total }} is just a name to look up. In Burxt
it is a real expression the compiler checks — which is page 4,
and the reason to keep reading.
Two rules that are BMX’s, though:
A slot must close on its own line.
Dear {{ customer
.name }},
BMX-E001 at 5: unterminated slot: no }} on this line
If slots could span lines, an unterminated one would look exactly like an ordinary paragraph — and you would find out from a reader.
A slot in a code block is not a slot.
```
{{ this is just text }}
```
That is what makes it possible to write documentation about BMX, in BMX.
No if, no loops
There is no {{#if}} and no {{#each}}. This is deliberate and it is worth a sentence, because
every other template language has them.
A template with control flow in it slowly becomes a program — and it is a program written in a tiny
language, with no types, no tests and no debugger. The host language already has if and while
and is much better at them. So: decide in your code, and pass the answer in.
Next: When BMX says no — why refusing is the feature, not the friction.