From 1066c884f3759d6592888ec364e799afab089aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Sat, 25 Jan 2025 20:55:01 +0100 Subject: [PATCH] book: add enum documentation --- book/src/creating_templates.md | 79 +++++++++++++++++++++++++++++ testing/tests/enum.rs | 93 ++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/book/src/creating_templates.md b/book/src/creating_templates.md index 5eb34c65..510906e5 100644 --- a/book/src/creating_templates.md +++ b/book/src/creating_templates.md @@ -118,6 +118,85 @@ recognized: struct HelloTemplate<'a> { ... } ``` +## Templating `enum`s + +You can add derive `Template`s for `struct`s and `enum`s. +If you add `#[template()]` only to the item itself, both item kinds work exactly the same. +But with `enum`s you also have the option to add a specialized implementation to one, some, +or all variants: + +```rust +#[derive(Debug, Template)] +#[template(path = "area.txt")] +enum Area { + Square(f32), + Rectangle { a: f32, b: f32 }, + Circle { radius: f32 }, +} +``` + +```jinja2 +{%- match self -%} + {%- when Self::Square(side) -%} + {{side}}^2 + {%- when Self::Rectangle { a, b} -%} + {{a}} * {{b}} + {%- when Self::Circle { radius } -%} + pi * {{radius}}^2 +{%- endmatch -%} +``` + +will give you the same results as: + +```rust +#[derive(Template, Debug)] +#[template(ext = "txt")] +enum AreaPerVariant { + #[template(source = "{{self.0}}^2")] + Square(f32), + #[template(source = "{{a}} * {{b}}")] + Rectangle { a: f32, b: f32 }, + #[template(source = "pi * {{radius}}^2")] + Circle { radius: f32 }, +} +``` + +As you can see with the `ext` attribute, `enum` variants inherit most settings of the `enum`: +`config`, `escape`, `ext`, `syntax`, and `whitespace`. +Not inherited are: `block`, and `print`. + +If there is no `#[template]` annotation for an `enum` variant, +then the `enum` needs a default implementation, which will be used if `self` is this variant. +A good compromise between annotating only the template, or all its variants, +might be using the `block` argument on the members: + +```rust +#[derive(Template, Debug)] +#[template(path = "area.txt")] +enum AreaWithBlocks { + #[template(block = "square")] + Square(f32), + #[template(block = "rectangle")] + Rectangle { a: f32, b: f32 }, + #[template(block = "circle")] + Circle { radius: f32 }, +} +``` + +```jinja2 +{%- block square -%} + {{self.0}}^2 +{%- endblock -%} + +{%- block rectangle -%} + {{a}} * {{b}} +{%- endblock -%} + +{%- block circle -%} + pi * {{radius}}^2 +{%- endblock -%} +``` + ## Documentation as template code [#documentation-as-template-code]: #documentation-as-template-code diff --git a/testing/tests/enum.rs b/testing/tests/enum.rs index 3a9341c8..0723af0e 100644 --- a/testing/tests/enum.rs +++ b/testing/tests/enum.rs @@ -3,6 +3,99 @@ use std::fmt::{Debug, Display}; use rinja::Template; +#[test] +fn test_book_example() { + #[derive(Template, Debug)] + #[template( + source = " + {%- match self -%} + {%- when Self::Square(side) -%} {{side}}^2 + {%- when Self::Rectangle { a, b} -%} {{a}} * {{b}} + {%- when Self::Circle { radius } -%} pi * {{radius}}^2 + {%- endmatch -%} + ", + ext = "txt" + )] + enum AreaWithMatch { + #[template(source = "{{self.0}}^2", ext = "txt")] + Square(f32), + #[template(source = "{{a}} * {{b}}", ext = "txt")] + Rectangle { a: f32, b: f32 }, + #[template(source = "pi * {{radius}}^2", ext = "txt")] + Circle { radius: f32 }, + } + + assert_eq!(AreaWithMatch::Square(2.0).render().unwrap(), "2^2"); + assert_eq!( + AreaWithMatch::Rectangle { a: 1.0, b: 2.0 } + .render() + .unwrap(), + "1 * 2", + ); + assert_eq!( + AreaWithMatch::Circle { radius: 3.0 }.render().unwrap(), + "pi * 3^2" + ); + + #[derive(Template, Debug)] + enum AreaPerVariant { + #[template(source = "{{self.0}}^2", ext = "txt")] + Square(f32), + #[template(source = "{{a}} * {{b}}", ext = "txt")] + Rectangle { a: f32, b: f32 }, + #[template(source = "pi * {{radius}}^2", ext = "txt")] + Circle { radius: f32 }, + } + + assert_eq!(AreaPerVariant::Square(2.0).render().unwrap(), "2^2"); + assert_eq!( + AreaPerVariant::Rectangle { a: 1.0, b: 2.0 } + .render() + .unwrap(), + "1 * 2", + ); + assert_eq!( + AreaPerVariant::Circle { radius: 3.0 }.render().unwrap(), + "pi * 3^2" + ); + + #[derive(Template, Debug)] + #[template( + source = " + {%- block square -%} + {{self.0}}^2 + {%- endblock -%} + {%- block rectangle -%} + {{a}} * {{b}} + {%- endblock -%} + {%- block circle -%} + pi * {{radius}}^2 + {%- endblock -%} + ", + ext = "txt" + )] + enum AreaWithBlocks { + #[template(block = "square")] + Square(f32), + #[template(block = "rectangle")] + Rectangle { a: f32, b: f32 }, + #[template(block = "circle")] + Circle { radius: f32 }, + } + + assert_eq!(AreaWithBlocks::Square(2.0).render().unwrap(), "2^2"); + assert_eq!( + AreaWithBlocks::Rectangle { a: 1.0, b: 2.0 } + .render() + .unwrap(), + "1 * 2", + ); + assert_eq!( + AreaWithBlocks::Circle { radius: 3.0 }.render().unwrap(), + "pi * 3^2" + ); +} + #[test] fn test_simple_enum() { #[derive(Template, Debug)]