Switch documentation to one-sentence-per-line ()

This commit is contained in:
Chris Wong 2023-02-12 22:19:56 +11:00 committed by GitHub
parent daa43549ee
commit 4f14db7415
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 64 additions and 149 deletions

View file

@ -1,14 +1,11 @@
# Control structures # Control structures
Maud provides various control structures Maud provides various control structures for adding dynamic elements to your templates.
for adding dynamic elements to your templates.
## Branching with `@if` and `@else` ## Branching with `@if` and `@else`
Use `@if` and `@else` to branch on a boolean expression. Use `@if` and `@else` to branch on a boolean expression.
As with Rust, As with Rust, braces are mandatory and the `@else` clause is optional.
braces are mandatory
and the `@else` clause is optional.
```rust ```rust
#[derive(PartialEq)] #[derive(PartialEq)]

View file

@ -37,8 +37,7 @@ html! {
# ; # ;
``` ```
The result will be rendered with HTML syntax The result will be rendered with HTML syntax `<br>` not `<br />`.
`<br>` not `<br />`.
## Custom elements and `data` attributes ## Custom elements and `data` attributes
@ -62,11 +61,9 @@ html! {
## Non-empty attributes: `title="yay"` ## Non-empty attributes: `title="yay"`
Add attributes using the syntax: Add attributes using the syntax: `attr="value"`.
`attr="value"`.
You can attach any number of attributes to an element. You can attach any number of attributes to an element.
The values must be quoted: The values must be quoted: they are parsed as string literals.
they are parsed as string literals.
```rust ```rust
# let _ = maud:: # let _ = maud::
@ -89,10 +86,8 @@ html! {
## Optional attributes: `title=[Some("value")]` ## Optional attributes: `title=[Some("value")]`
Add optional attributes to an element using `attr=[value]` syntax, Add optional attributes to an element using `attr=[value]` syntax, with *square* brackets.
with *square* brackets. These are only rendered if the value is `Some<T>`, and entirely omitted if the value is `None`.
These are only rendered if the value is `Some<T>`,
and entirely omitted if the value is `None`.
```rust ```rust
# let _ = maud:: # let _ = maud::
@ -124,20 +119,15 @@ html! {
# ; # ;
``` ```
Before version 0.22.2, Before version 0.22.2, Maud required a `?` suffix on empty attributes: `checked?`.
Maud required a `?` suffix on empty attributes: This is no longer necessary ([#238]), but still supported for backward compatibility.
`checked?`.
This is no longer necessary ([#238]),
but still supported for backward compatibility.
[#238]: https://github.com/lambda-fairy/maud/pull/238 [#238]: https://github.com/lambda-fairy/maud/pull/238
## Classes and IDs: `.foo` `#bar` ## Classes and IDs: `.foo` `#bar`
Add classes and IDs to an element Add classes and IDs to an element using `.foo` and `#bar` syntax.
using `.foo` and `#bar` syntax. You can chain multiple classes and IDs together, and mix and match them with other attributes:
You can chain multiple classes and IDs together,
and mix and match them with other attributes:
```rust ```rust
# let _ = maud:: # let _ = maud::
@ -147,9 +137,7 @@ html! {
# ; # ;
``` ```
In Rust 2021, In Rust 2021, the `#` symbol must be preceded by a space, to avoid conflicts with [reserved syntax]:
the `#` symbol must be preceded by a space,
to avoid conflicts with [reserved syntax]:
[reserved syntax]: https://doc.rust-lang.org/edition-guide/rust-2021/reserving-syntax.html [reserved syntax]: https://doc.rust-lang.org/edition-guide/rust-2021/reserving-syntax.html
@ -166,8 +154,7 @@ html! {
``` ```
The classes and IDs can be quoted. The classes and IDs can be quoted.
This is useful for names with numbers or symbols This is useful for names with numbers or symbols which otherwise wouldn't parse:
which otherwise wouldn't parse:
```rust ```rust
# let _ = maud:: # let _ = maud::
@ -179,9 +166,7 @@ html! {
## Implicit `div` elements ## Implicit `div` elements
If the element name is omitted, If the element name is omitted, but there is a class or ID, then it is assumed to be a `div`.
but there is a class or ID,
then it is assumed to be a `div`.
```rust ```rust
# let _ = maud:: # let _ = maud::

View file

@ -3,8 +3,7 @@
## What is the origin of the name "Maud"? ## What is the origin of the name "Maud"?
Maud is named after a [character] from *My Little Pony: Friendship is Magic*. Maud is named after a [character] from *My Little Pony: Friendship is Magic*.
It does not refer to the [poem] by Alfred Tennyson, It does not refer to the [poem] by Alfred Tennyson, though other people have brought that up in the past.
though other people have brought that up in the past.
Here are some reasons why I chose this name: Here are some reasons why I chose this name:
@ -12,8 +11,7 @@ Here are some reasons why I chose this name:
* The library is efficient and austere, like the character; * The library is efficient and austere, like the character;
* Google used to maintain a site called ["HTML5 Rocks"], * Google used to maintain a site called ["HTML5 Rocks"], and Maud (the character) is a geologist.
and Maud (the character) is a geologist.
[character]: http://mlp.wikia.com/wiki/Maud_Pie [character]: http://mlp.wikia.com/wiki/Maud_Pie
[poem]: https://en.wikipedia.org/wiki/Maud_and_other_poems [poem]: https://en.wikipedia.org/wiki/Maud_and_other_poems
@ -24,49 +22,32 @@ Here are some reasons why I chose this name:
Good question! In fact, Maud did work this way in the past. Good question! In fact, Maud did work this way in the past.
But it's hard to support buffer reuse in an ergonomic way. But it's hard to support buffer reuse in an ergonomic way.
The approaches I tried The approaches I tried either involved too much boilerplate, or caused mysterious lifetime issues, or both.
either involved too much boilerplate,
or caused mysterious lifetime issues,
or both.
Moreover, Maud's allocation pattern—with small, short-lived buffers—follow the fast path in modern allocators. Moreover, Maud's allocation pattern—with small, short-lived buffers—follow the fast path in modern allocators.
These reasons are why I changed `html!` to return a `String` in version 0.11. These reasons are why I changed `html!` to return a `String` in version 0.11.
That said, That said, Rust has changed a lot since then, and some of those old assumptions might no longer hold today.
Rust has changed a lot since then, So this decision could be revisited prior to the 1.0 release.
and some of those old assumptions
might no longer hold today.
So this decision could be revisited
prior to the 1.0 release.
## Why is Maud written as a procedural macro? Can't it use `macro_rules!` instead? ## Why is Maud written as a procedural macro? Can't it use `macro_rules!` instead?
This is certainly possible, and indeed the [Horrorshow] library works this way. This is certainly possible, and indeed the [Horrorshow] library works this way.
I use procedural macros because they are more flexible. I use procedural macros because they are more flexible.
There are some syntax constructs in Maud that are hard to parse with `macro_rules!`; There are some syntax constructs in Maud that are hard to parse with `macro_rules!`; better diagnostics are a bonus as well.
better diagnostics are a bonus as well.
[Horrorshow]: https://github.com/Stebalien/horrorshow-rs [Horrorshow]: https://github.com/Stebalien/horrorshow-rs
## Maud has had a lot of releases so far. When will it reach 1.0? ## Maud has had a lot of releases so far. When will it reach 1.0?
I originally planned to cut a 1.0 I originally planned to cut a 1.0 after implementing stable support.
after implementing stable support. But now that's happened, I've realized that there are a couple design questions that I'd like to resolve before marking that milestone.
But now that's happened,
I've realized that there are a couple design questions
that I'd like to resolve
before marking that milestone.
Expect a blog post on this topic Very Soon®. Expect a blog post on this topic Very Soon®.
## Why doesn't Maud implement [context-aware escaping]? ## Why doesn't Maud implement [context-aware escaping]?
I agree that context-aware escaping is very important, I agree that context-aware escaping is very important, especially for the kind of small-scale development that Maud is used for.
especially for the kind of small-scale development But it's a complex feature, with security implications, so I want to take the time to get it right.
that Maud is used for.
But it's a complex feature,
with security implications,
so I want to take the time
to get it right.
Please follow [#181] for the latest developments! Please follow [#181] for the latest developments!

View file

@ -2,8 +2,7 @@
## Add Maud to your project ## Add Maud to your project
Once Rust is set up, Once Rust is set up, create a new project with Cargo:
create a new project with Cargo:
```sh ```sh
cargo new --bin pony-greeter cargo new --bin pony-greeter
@ -31,15 +30,12 @@ fn main() {
} }
``` ```
`html!` takes a single argument: `html!` takes a single argument: a template using Maud's custom syntax.
a template using Maud's custom syntax. This call expands to an expression of type [`Markup`][Markup], which can then be converted to a `String` using `.into_string()`.
This call expands to an expression of type [`Markup`][Markup],
which can then be converted to a `String` using `.into_string()`.
[Markup]: https://docs.rs/maud/*/maud/type.Markup.html [Markup]: https://docs.rs/maud/*/maud/type.Markup.html
Run this program with `cargo run`, Run this program with `cargo run`, and you should get the following:
and you should get the following:
```html ```html
<p>Hi, Lyra!</p> <p>Hi, Lyra!</p>
@ -49,13 +45,7 @@ Congrats you've written your first Maud program!
## Which version of Rust? ## Which version of Rust?
While Maud works well While Maud works well on both stable and [nightly] versions of Rust, the error messages are slightly better on nightly.
on both stable and [nightly] versions For this reason, it is recommended to develop using nightly Rust, but test and deploy using stable.
of Rust,
the error messages are slightly better
on nightly.
For this reason,
it is recommended to develop using nightly Rust,
but test and deploy using stable.
[nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html [nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html

View file

@ -16,40 +16,30 @@ html! {
``` ```
Maud is an HTML [template engine] for Rust. Maud is an HTML [template engine] for Rust.
It's implemented as a macro, `html!`, It's implemented as a macro, `html!`, which compiles your markup to specialized Rust code.
which compiles your markup to specialized Rust code. This unique approach makes Maud templates fast, type-safe, and easy to deploy.
This unique approach makes Maud templates
fast, type-safe, and easy to deploy.
[template engine]: https://www.simple-is-better.org/template/ [template engine]: https://www.simple-is-better.org/template/
## Tight integration with Rust ## Tight integration with Rust
Since Maud is a Rust macro, Since Maud is a Rust macro, it can borrow most of its features from the host language.
it can borrow most of its features from the host language.
Pattern matching and `for` loops work as they do in Rust. Pattern matching and `for` loops work as they do in Rust.
There is no need to derive JSON conversions, There is no need to derive JSON conversions, as your templates can work with Rust values directly.
as your templates can work with Rust values directly.
## Type safety ## Type safety
Your templates are checked by the compiler, Your templates are checked by the compiler, just like the code around them.
just like the code around them. Any typos will be caught at compile time, not after your app has already started.
Any typos will be caught at compile time,
not after your app has already started.
## Minimal runtime ## Minimal runtime
Since most of the work happens at compile time, Since most of the work happens at compile time, the runtime footprint is small.
the runtime footprint is small. The Maud runtime library, including integration with the [Rocket] and [Actix] web frameworks, is around 100 SLoC.
The Maud runtime library,
including integration with the [Rocket] and [Actix] web frameworks,
is around 100 SLoC.
[Rocket]: https://rocket.rs/ [Rocket]: https://rocket.rs/
[Actix]: https://actix.rs/ [Actix]: https://actix.rs/
## Simple deployment ## Simple deployment
There is no need to track separate template files, There is no need to track separate template files, since all relevant code is linked into the final executable.
since all relevant code is linked into the final executable.

View file

@ -1,8 +1,7 @@
# Partials # Partials
Maud does not have a built-in concept of partials or sub-templates. Maud does not have a built-in concept of partials or sub-templates.
Instead, Instead, you can compose your markup with any function that returns `Markup`.
you can compose your markup with any function that returns `Markup`.
The following example defines a `header` and `footer` function. The following example defines a `header` and `footer` function.
These functions are combined to form the final `page`. These functions are combined to form the final `page`.

View file

@ -8,8 +8,7 @@ Feel free to use these snippets in your own project!
## Example: a shorthand for including CSS stylesheets ## Example: a shorthand for including CSS stylesheets
When writing a web page, When writing a web page, it can be annoying to write `link rel="stylesheet"` over and over again.
it can be annoying to write `link rel="stylesheet"` over and over again.
This example provides a shorthand for linking to CSS stylesheets. This example provides a shorthand for linking to CSS stylesheets.
```rust ```rust
@ -29,15 +28,12 @@ impl Render for Css {
## Example: a wrapper that calls `std::fmt::Debug` ## Example: a wrapper that calls `std::fmt::Debug`
When debugging an application, When debugging an application, it can be useful to see its internal state.
it can be useful to see its internal state.
But these internal data types often don't implement `Display`. But these internal data types often don't implement `Display`.
This wrapper lets us use the [`Debug`][Debug] trait instead. This wrapper lets us use the [`Debug`][Debug] trait instead.
To avoid extra allocation, To avoid extra allocation, we override the `.render_to()` method instead of `.render()`.
we override the `.render_to()` method instead of `.render()`. This doesn't do any escaping by default, so we wrap the output in an `Escaper` as well.
This doesn't do any escaping by default,
so we wrap the output in an `Escaper` as well.
```rust ```rust
use maud::{Escaper, html, Render}; use maud::{Escaper, html, Render};
@ -57,11 +53,9 @@ impl<T: fmt::Debug> Render for Debug<T> {
## Example: rendering Markdown using `pulldown-cmark` and `ammonia` ## Example: rendering Markdown using `pulldown-cmark` and `ammonia`
[`pulldown-cmark`][pulldown-cmark] is a popular library [`pulldown-cmark`][pulldown-cmark] is a popular library for converting Markdown to HTML.
for converting Markdown to HTML.
We also use the [`ammonia`][ammonia] library, We also use the [`ammonia`][ammonia] library, which sanitizes the resulting markup.
which sanitizes the resulting markup.
```rust ```rust
use ammonia; use ammonia;

View file

@ -20,8 +20,7 @@ html! {
``` ```
Arbitrary Rust code can be included in a splice by using a [block]. Arbitrary Rust code can be included in a splice by using a [block].
This can be helpful for complex expressions This can be helpful for complex expressions that would be difficult to read otherwise.
that would be difficult to read otherwise.
```rust ```rust
# struct Foo; # struct Foo;
@ -61,8 +60,7 @@ html! {
# ; # ;
``` ```
To concatenate multiple values within an attribute, To concatenate multiple values within an attribute, wrap the whole thing in braces.
wrap the whole thing in braces.
This syntax is useful for building URLs. This syntax is useful for building URLs.
```rust ```rust
@ -95,14 +93,10 @@ html! {
### What can be spliced? ### What can be spliced?
You can splice any value that implements [`Render`][Render]. You can splice any value that implements [`Render`][Render].
Most primitive types (such as `str` and `i32`) implement this trait, Most primitive types (such as `str` and `i32`) implement this trait, so they should work out of the box.
so they should work out of the box.
To get this behavior for a custom type, To get this behavior for a custom type, you can implement the [`Render`][Render] trait by hand.
you can implement the [`Render`][Render] trait by hand. The [`PreEscaped`][PreEscaped] wrapper type, which outputs its argument without escaping, works this way.
The [`PreEscaped`][PreEscaped] wrapper type,
which outputs its argument without escaping,
works this way.
See the [traits](render-trait.md) section for details. See the [traits](render-trait.md) section for details.
```rust ```rust
@ -121,8 +115,7 @@ html! {
## Toggles: `[foo]` ## Toggles: `[foo]`
Use `[foo]` syntax to show or hide something Use `[foo]` syntax to show or hide something based on a boolean expression `foo`.
based on a boolean expression `foo`.
This works on empty attributes: This works on empty attributes:

View file

@ -3,8 +3,7 @@
## Text ## Text
Literal strings use the same syntax as Rust. Literal strings use the same syntax as Rust.
Wrap them in double quotes, Wrap them in double quotes, and use a backslash for escapes.
and use a backslash for escapes.
```rust ```rust
# let _ = maud:: # let _ = maud::
@ -16,9 +15,7 @@ html! {
## Raw strings ## Raw strings
If the string is long, If the string is long, or contains many special characters, then it may be worth using [raw strings] instead:
or contains many special characters,
then it may be worth using [raw strings] instead:
```rust ```rust
# let _ = maud:: # let _ = maud::
@ -41,11 +38,9 @@ html! {
## Escaping and `PreEscaped` ## Escaping and `PreEscaped`
By default, By default, HTML special characters are escaped automatically.
HTML special characters are escaped automatically.
Wrap the string in `(PreEscaped())` to disable this escaping. Wrap the string in `(PreEscaped())` to disable this escaping.
(See the section on [splices](splices-toggles.md) to (See the section on [splices](splices-toggles.md) to learn more about how this works.)
learn more about how this works.)
```rust ```rust
use maud::PreEscaped; use maud::PreEscaped;
@ -59,9 +54,7 @@ html! {
## The `DOCTYPE` constant ## The `DOCTYPE` constant
If you want to add a `<!DOCTYPE html>` declaration to your page, If you want to add a `<!DOCTYPE html>` declaration to your page, you may use the `maud::DOCTYPE` constant instead of writing it out by hand:
you may use the `maud::DOCTYPE` constant
instead of writing it out by hand:
```rust ```rust
use maud::DOCTYPE; use maud::DOCTYPE;

View file

@ -1,7 +1,6 @@
# Web framework integration # Web framework integration
Maud includes support for these web frameworks: Maud includes support for these web frameworks: [Actix], [Rocket], [Rouille], and [Tide].
[Actix], [Rocket], [Rouille], and [Tide].
[Actix]: https://actix.rs/ [Actix]: https://actix.rs/
[Rocket]: https://rocket.rs/ [Rocket]: https://rocket.rs/
@ -19,8 +18,7 @@ maud = { version = "*", features = ["actix-web"] }
# ... # ...
``` ```
Actix request handlers can use a `Markup` Actix request handlers can use a `Markup` that implements the `actix_web::Responder` trait.
that implements the `actix_web::Responder` trait.
```rust,no_run ```rust,no_run
use actix_web::{get, App, HttpServer, Result as AwResult}; use actix_web::{get, App, HttpServer, Result as AwResult};
@ -49,8 +47,7 @@ async fn main() -> io::Result<()> {
# Rocket # Rocket
Rocket works in a similar way, Rocket works in a similar way, except using the `rocket` feature:
except using the `rocket` feature:
```toml ```toml
# ... # ...
@ -59,8 +56,7 @@ maud = { version = "*", features = ["rocket"] }
# ... # ...
``` ```
This adds a `Responder` implementation for the `Markup` type, This adds a `Responder` implementation for the `Markup` type, so you can return the result directly:
so you can return the result directly:
```rust,no_run ```rust,no_run
#![feature(decl_macro)] #![feature(decl_macro)]
@ -84,8 +80,7 @@ fn main() {
# Rouille # Rouille
Unlike with the other frameworks, Unlike with the other frameworks, Rouille doesn't need any extra features at all!
Rouille doesn't need any extra features at all!
Calling `Response::html` on the rendered `Markup` will Just Work®. Calling `Response::html` on the rendered `Markup` will Just Work®.
```rust,no_run ```rust,no_run
@ -118,10 +113,8 @@ maud = { version = "*", features = ["tide"] }
# ... # ...
``` ```
This adds an implementation of `From<PreEscaped<String>>` This adds an implementation of `From<PreEscaped<String>>` for the `Response` struct.
for the `Response` struct. Once provided, callers may return results of `html!` directly as responses:
Once provided,
callers may return results of `html!` directly as responses:
```rust,no_run ```rust,no_run
use maud::html; use maud::html;