-
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
346 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
nav: | ||
- 'index.md' | ||
- 'variables.md' | ||
- 'if-statements.md' | ||
- 'for-loops.md' | ||
- 'functions.md' | ||
- '...' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Template cache | ||
|
||
Templates are compiled and evaluated on the fly. This is handy for local development, allowing you to modify the template without recompiling the Rust app or restarting the web server, but in production could be an unnecessary performance hindrance. | ||
|
||
The template cache makes sure a template is compiled only once. All subsequent executions of the template will use an internal representation and are much faster to run. | ||
|
||
## Using the cache | ||
|
||
To use the template cache, templates must be stored on disk, for example in a `templates` directory. Loading a template should use the [`Template::load`](https://docs.rs/rwf/latest/rwf/view/template/struct.Template.html#method.load) function: | ||
|
||
```rust | ||
let template = Template::load("templates/index.html")?; | ||
``` | ||
|
||
The first time the template is loaded, it will be fetched from disk and compiled. Once compiled, it will be stored in the cache to be reused by all subsequent calls to [`Template::load`](https://docs.rs/rwf/latest/rwf/view/template/struct.Template.html#method.load). | ||
|
||
## Enable the cache | ||
|
||
The template cache is disabled by default. To enable it, toggle the `cache_templates` setting in [configuration](../../../configuration). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# For loops | ||
|
||
Rwf templates have only one kind of for loop: for each. This allows writing more reliable templates, and to avoid common bugs like infinite loops, which will stall a web app in production. | ||
|
||
A for loop can iterate over a list of values, for example: | ||
|
||
```erb | ||
<ul> | ||
<% for value in list %> | ||
<li><%= value %></li> | ||
<% end %> | ||
</ul> | ||
``` | ||
|
||
Template lists, unlike Rust's `Vec`, can hold [variables](../variables) of different data types, and are dynamically evaluted at runtime: | ||
|
||
=== "Template" | ||
```erb | ||
<% for value in ["one", 2 * 5, 3/1.5] %> | ||
<%= value %> | ||
<% end %> | ||
``` | ||
=== "Output" | ||
``` | ||
one | ||
10 | ||
2.0 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Functions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# If statements | ||
|
||
If statements allow you to control the flow of templates, conditionally displaying some elements while hiding others. For example, if a [variable](../variables) is "falsy", you can hide entire sections of your website: | ||
|
||
```erb | ||
<% if logged_in %> | ||
<!-- profile page --> | ||
<% else %> | ||
<!-- login page --> | ||
<% end %> | ||
``` | ||
|
||
If statements start with `if` and must always finish with `end`. | ||
|
||
## Expressions | ||
|
||
If statements support evaluating large expressions for truthiness, for example: | ||
|
||
```erb | ||
<% if var.lower + "_" + bar.upper == "lo_HI" %> | ||
<!-- do something --> | ||
<% end %> | ||
``` | ||
|
||
While it's advisable to write simple if statements and delegate complex logic to views where the Rust compiler can be more helpful, Rwf template language is almost [Turing-complete](https://en.wikipedia.org/wiki/Turing_completeness) and can be used to write arbitrarily complex templates. | ||
|
||
### Operator precendence | ||
|
||
Templates respect operator precedence, e.g., multiplication is performed before addition, unless parentheses are specified (which are also supported). | ||
|
||
## Else If | ||
|
||
If statements support else if blocks (written as `elsif`), evaluating multiple expressions and executing the first one which evaluates to true: | ||
|
||
```erb | ||
<% if one %> | ||
<!-- one --> | ||
<% elsif two %> | ||
<!-- two --> | ||
<% elsif three %> | ||
<!-- three --> | ||
<% else %> | ||
<!-- I guess it's four? ---> | ||
<% end %> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,47 @@ | ||
# Templates overview | ||
# Templates overview | ||
|
||
Dynamic templates are a mix of HTML and a programming language which directs how the HTML is displayed. For example, if you have a profile page for your web app users, you would want each of your users to have a page unique to them. To achieve this, you would write only one template and substitute unique aspects of each using template variables, for example: | ||
|
||
```erb | ||
<div class="profile"> | ||
<h2><%= username %></h2> | ||
<p><%= bio %></p> | ||
</div> | ||
``` | ||
|
||
The variables `username` and `bio` can be substituded for values unique to each of your users, for example: | ||
|
||
=== "Rust" | ||
```rust | ||
use rwf::prelude::*; | ||
|
||
let template = Template::from_str(r#" | ||
<div class="profile"> | ||
<h2><%= username %></h2> | ||
<p><%= bio %></p> | ||
</div> | ||
"#)?; | ||
|
||
let html = template.render([ | ||
("username", "Alice"), | ||
("bio", "I like turtles") | ||
])?; | ||
|
||
println!("{}", html); | ||
``` | ||
=== "Output" | ||
```html | ||
<div class="profile"> | ||
<h2>Alice</h2> | ||
<p>I like turtles</p> | ||
</div> | ||
``` | ||
|
||
Templates help reuse HTML (and CSS, JavaScript) just like regular functions and structs help | ||
reuse code. | ||
|
||
## Learn more | ||
|
||
- [Variables](variables) | ||
- [For loops](for-loops) | ||
- [If statements](if-statements) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Nomenclature |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
# Variables | ||
|
||
Template variables are used to substitute unique information into a reusable template. Rwf supports variables of different kinds, like strings, numbers, lists, and hashes. Complex variables like hashes can be iterated through using [for loops](../for-loops). | ||
|
||
## Using variables | ||
|
||
Using variables in your templates is typically done by "printing" them, or outputting them, into the template text, by placing them between `<%=` and `%>` tags: | ||
|
||
```erb | ||
<%= variable %> | ||
``` | ||
|
||
The `<%=` tag indicates what follows is an [expression](../nomenclature), which should be evaluated and converted to text for displaying purposes. | ||
|
||
The `%>` tag is not specific to printing variables, and indicates the end of a code block inside a template. What follows that tag is just regular text which has no special meaning. | ||
|
||
## Defining variables | ||
|
||
A variable is defined when a template is rendered. Using one of many possible ways to define a [context](../context), the variable is given a value at runtime: | ||
|
||
=== "Rust" | ||
```rust | ||
let template = Template::from_str("<%= variable %>")?; | ||
let string = template.render([ | ||
("variable", "I love pancakes for dinner."), | ||
])?; | ||
println!("{}", string); | ||
``` | ||
=== "Output" | ||
``` | ||
I love pancakes for dinner. | ||
``` | ||
|
||
### Missing variables | ||
|
||
It's not uncommon to forget to define variables, epecially if a template is large, or used in multiple places in the app where some variables don't have a known value. | ||
|
||
If an undefined variable is used in a template, Rwf will throw a runtime error. This is good for debugging issues when variables are unintentionally forgotten by the developer. However, if the variable is not always available, you can check if it's defined first: | ||
|
||
```erb | ||
<% if variable %> | ||
<p><%= variable %></p> | ||
<% end %> | ||
``` | ||
|
||
Due to the nature of [if statements](../if-statements), if the variable is defined and evaluates to a "falsy" value, e.g. `0`, `""` (empty string), `null`, etc., the if statement will not be executed either. This is helpful for handling many similar cases without having to write complex statements. | ||
|
||
## Supported data types | ||
|
||
Rwf variables support most Rust data types. The conversion between Rust and the template language happens automatically. | ||
|
||
### Number | ||
|
||
Rwf supports two kinds of numbers: integers and floating points. | ||
|
||
An integer is any whole number, negative or positive (including zero). Rust has many integer types, e.g. `i8`, `i32`, `u64`, etc., but the template language converts all of them to an 64-bit singed integer: | ||
|
||
=== "Template" | ||
```erb | ||
<%= 500 %> | ||
``` | ||
=== "Output" | ||
``` | ||
500 | ||
``` | ||
|
||
Rust's `f32` and `f64` are converted to 64-bit double precision floating point. Operations between integers and floating points are supported, the final result being a float: | ||
|
||
=== "Template" | ||
```erb | ||
<%= 500 + 1.5 %> | ||
``` | ||
=== "Output" | ||
``` | ||
501.5 | ||
``` | ||
|
||
Numbers can be [converted](../functions) to strings, floored, ceiled and rounded, for example: | ||
|
||
=== "Template" | ||
```erb | ||
<%= 123.45.round.to_s %> | ||
``` | ||
=== "Output" | ||
``` | ||
123 | ||
``` | ||
|
||
### Strings | ||
|
||
Using strings in templates can be used in two ways: with the `<%=` (print) operator, which outputs the string, escaping any dangerous HTML characters, e.g. `<` becomes `<`, or using `<%-` which performs no conversions and prints the string as-is. | ||
|
||
#### String security | ||
|
||
Escaping HTML characters is a good idea in cases where your users are the ones supplying the value of the string. This prevents script injection attacks, e.g. users placing malicious code on your website. | ||
|
||
Unless you're sure about the provinance of a string, use `<%=` to output it in templates. | ||
|
||
### Boolean | ||
|
||
Boolean variables can either be `true` or `false`. They map directly to Rust's `bool` data type. | ||
|
||
### Lists | ||
|
||
Lists are arrays of other template variables, including other lists, strings, numbers, and hashes. In templates, lists can be defined by using square brackets, and iterated on using [for loops](../for-loops), for example: | ||
|
||
=== "Template" | ||
```erb | ||
<% for item in [1, 2, "three"] %> | ||
<%= item %> | ||
<% end %> | ||
``` | ||
=== "Output" | ||
``` | ||
1 | ||
2 | ||
three | ||
``` | ||
|
||
Rwf lists are flexible and can contain multiple data types. This separates them from Rust's `Vec` and slices which can only hold one kind of data. | ||
|
||
You can also access a specific element in a list by indexing into it with the dot(`.`) notation: | ||
|
||
```erb | ||
<%= list.1 %> | ||
``` | ||
|
||
Lists are 0-indexed, so the above example accesses the second element in the list. | ||
|
||
### Hashes | ||
|
||
Hashes, also known as dicts or hash tables, are a key/value storage data type. Unlike a list, it contains a mapping between a value (the key), and a value. Values can be accessed by knowing a key, or by iterating through the entire hash with a [for loop](../for-loops): | ||
|
||
```erb | ||
<p><%= user.name %></p> | ||
<p><%= user.email %></p> | ||
``` | ||
|
||
Rwf hashes use the dot (`.`) notation to access values in a hash. In this example, the `user` is a hash, and `name` and `email` are keys. | ||
|
||
## Truthy vs. falsy | ||
|
||
Variables are often used in [if statements](../if-statements) to decide whether to execute some code or not. To make the template language less verbose, variables can be evaluted for truthiness without calling explicit functions depending on their data type. | ||
|
||
The following variables and data types evaluate to false: | ||
|
||
| Data type | Value | | ||
|-----------|----------| | ||
| Integer | `0` | | ||
| Float | `0.0` | | ||
| Boolean | `false` | | ||
| String | `""` (empty) | | ||
| List | `[]` (emtpy) | | ||
| Hash | `{}` (empty) | | ||
|
||
All other variables evaluate to true. | ||
|
||
## Learn more | ||
|
||
- [If statements](../if-statements) | ||
- [For loops](../for-loops) | ||
- [Functions](../functions) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters