Skip to content

Commit

Permalink
Added an example for custom errors
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Nov 6, 2024
1 parent e1989c5 commit 90a5a2e
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ the `cargo run` command. Alternatively you can do `cargo run -p example-name`.
* [autoreload](autoreload): shows how to use auto reloading.
* [build-script](build-script): Demonstrates how to generate Rust code with MiniJinja in build scripts.
* [call-block-function](call-block-function): Shows how to use the `{% call %}` block with a custom function.
* [custom-error](custom-error): shows how custom errors can be thrown and detected.
* [custom-loader](custom-loader): shows how to load templates dynamically at runtime with a custom loader.
* [debug](debug): contains an example showing the built-in `debug()` function.
* [deserialize](deserialize): demonstrates how you can deserialize directly from a value.
Expand Down
10 changes: 10 additions & 0 deletions examples/custom-error/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "custom-error"
version = "0.1.0"
edition = "2018"
publish = false

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
minijinja = { path = "../../minijinja" }
8 changes: 8 additions & 0 deletions examples/custom-error/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# custom-error

This example demonstrates how custom errors can be emitted in templates and
then detected later to customize the rendering of errors.

```console
$ cargo run
```
77 changes: 77 additions & 0 deletions examples/custom-error/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use std::fmt;

use minijinja::{context, Environment, Error, ErrorKind};

#[derive(Debug)]
struct UserError(String, usize);

impl UserError {
fn code(&self) -> usize {
self.1
}

fn message(&self) -> &str {
&self.0
}
}

impl fmt::Display for UserError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "user error: {}", self.0)
}
}

impl std::error::Error for UserError {}

fn execute() -> Result<(), minijinja::Error> {
let mut env = Environment::new();
env.set_debug(true);
env.add_function(
"trigger_user_error",
|s: String, i: usize| -> Result<(), Error> {
Err(Error::from(ErrorKind::InvalidOperation).with_source(UserError(s, i)))
},
);
env.add_template(
"include.txt",
"{{ trigger_user_error('This really should not happen', 42) }}!",
)?;
env.add_template(
"hello.txt",
r#"
first line
{% for item in seq %}
{% include "include.txt" %}
{% endfor %}
last line
"#,
)?;
let template = env.get_template("hello.txt").unwrap();
let ctx = context! {
seq => vec![2, 4, 8],
};
println!("{}", template.render(&ctx)?);
Ok(())
}

fn main() {
if let Err(err) = execute() {
eprintln!("template error: {err:#}");

let mut err = &err as &dyn std::error::Error;
while let Some(next_err) = err.source() {
if let Some(user_err) = next_err.downcast_ref::<UserError>() {
eprintln!();
eprintln!("caused by a well known error:");
eprintln!(" message: {}", user_err.message());
eprintln!(" code: {}", user_err.code());
} else {
eprintln!();
eprintln!("caused by: {next_err:#}");
}
err = next_err;
}

std::process::exit(1);
}
}

0 comments on commit 90a5a2e

Please sign in to comment.