mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-02 07:20:55 +00:00
Merge pull request #37 from GuillaumeGomez/method-call
Favor methods over closure fields
This commit is contained in:
commit
ca85ef6050
@ -245,13 +245,11 @@ struct MyTemplate;
|
||||
|
||||
### Struct / trait implementations
|
||||
|
||||
Finally, we can invoke functions that are implementation methods of our
|
||||
template struct, by referencing `Self` (note the uppercase `S`) as the path,
|
||||
before calling our function:
|
||||
Finally, we can call methods of our template struct:
|
||||
|
||||
```rust
|
||||
#[derive(Template)]
|
||||
#[template(source = "{{ Self::foo(self, 123) }}", ext = "txt")]
|
||||
#[template(source = "{{ foo(123) }}", ext = "txt")]
|
||||
struct MyTemplate {
|
||||
count: u32,
|
||||
};
|
||||
@ -263,9 +261,8 @@ impl MyTemplate {
|
||||
}
|
||||
```
|
||||
|
||||
If the implemented method requires a reference to the struct itself,
|
||||
such as is demonstrated in the above example, we can pass `self`
|
||||
(note the lowercase `s`) as the first argument.
|
||||
You can also use `self.foo(123)`, or even `Self::foo(self, 123)`, as you see
|
||||
fit.
|
||||
|
||||
Similarly, using the `Self` path, we can also call any method belonging
|
||||
to a trait that has been implemented for our template struct:
|
||||
@ -286,6 +283,32 @@ impl Hello for MyTemplate {
|
||||
}
|
||||
```
|
||||
|
||||
If you want to call a closure which is a field, you'll need to follow Rust's
|
||||
syntax by surrounding the call with parens:
|
||||
|
||||
```rust
|
||||
#[derive(Template)]
|
||||
#[template(source = "{{ (closure)(12) }}", ext = "txt")]
|
||||
struct MyTemplate {
|
||||
closure: fn(i32) -> i32,
|
||||
}
|
||||
```
|
||||
|
||||
## Calling functions
|
||||
|
||||
If you only provide a function name, `rinja` will assume it's a method. If
|
||||
you want to call a method, you will need to use a path instead:
|
||||
|
||||
```jinja
|
||||
{# This is the equivalent of `self.method()`. #}
|
||||
{{ method() }}
|
||||
{# This is the equivalent of `self::function()`, which will call the
|
||||
`function` function from the current module. #}
|
||||
{{ self::function() }}
|
||||
{# This is the equivalent of `super::b::f()`. #}
|
||||
{{ super::b::f() }}
|
||||
```
|
||||
|
||||
## Template inheritance
|
||||
|
||||
Template inheritance allows you to build a base template with common
|
||||
|
@ -1622,7 +1622,7 @@ impl<'a> Generator<'a> {
|
||||
match sub_left {
|
||||
Expr::Var(name) => match self.locals.resolve(name) {
|
||||
Some(resolved) => buf.write(resolved),
|
||||
None => buf.write(format_args!("(&self.{})", normalize_identifier(name))),
|
||||
None => buf.write(format_args!("self.{}", normalize_identifier(name))),
|
||||
},
|
||||
_ => {
|
||||
self.visit_expr(ctx, buf, left)?;
|
||||
|
@ -1,19 +1,21 @@
|
||||
use rinja::Template;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(source = "{{ func(value) }}", ext = "txt")]
|
||||
#[template(source = "{{ b(value) }}", ext = "txt")]
|
||||
struct OneFunction {
|
||||
func: fn(&i32) -> i32,
|
||||
value: i32,
|
||||
value: u32,
|
||||
}
|
||||
|
||||
impl OneFunction {
|
||||
fn b(&self, x: &u32) -> u32 {
|
||||
self.value + x
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one_func() {
|
||||
let t = OneFunction {
|
||||
func: |&i| 2 * i,
|
||||
value: 123,
|
||||
};
|
||||
assert_eq!(t.render().unwrap(), "246");
|
||||
let t = OneFunction { value: 10 };
|
||||
assert_eq!(t.render().unwrap(), "20");
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
@ -127,3 +129,44 @@ fn test_do_not_move_fields() {
|
||||
};
|
||||
assert_eq!(x.render().unwrap(), "a");
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(source = "{{ (func)(value) }}", ext = "txt")]
|
||||
struct ClosureField {
|
||||
func: fn(&i32) -> i32,
|
||||
value: i32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_closure_field() {
|
||||
let t = ClosureField {
|
||||
func: |&i| 2 * i,
|
||||
value: 123,
|
||||
};
|
||||
assert_eq!(t.render().unwrap(), "246");
|
||||
}
|
||||
|
||||
fn single() -> &'static str {
|
||||
"a"
|
||||
}
|
||||
|
||||
mod sub_mod {
|
||||
pub fn sub_fn(v: i32) -> i32 {
|
||||
v * 2
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(
|
||||
source = "
|
||||
{{- self::single() -}}
|
||||
{{- sub_mod::sub_fn(3) -}}
|
||||
",
|
||||
ext = "txt"
|
||||
)]
|
||||
struct NotMethod;
|
||||
|
||||
#[test]
|
||||
fn test_not_method() {
|
||||
assert_eq!(NotMethod.render().unwrap(), "a6");
|
||||
}
|
||||
|
@ -304,15 +304,17 @@ fn test_slice_literal() {
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(source = "Hello, {{ world(\"123\", 4) }}!", ext = "txt")]
|
||||
struct FunctionRefTemplate {
|
||||
world: fn(s: &str, v: u8) -> String,
|
||||
struct FunctionRefTemplate;
|
||||
|
||||
impl FunctionRefTemplate {
|
||||
fn world(&self, s: &str, v: u8) -> String {
|
||||
format!("world({s}, {v})")
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_func_ref_call() {
|
||||
let t = FunctionRefTemplate {
|
||||
world: |s, r| format!("world({s}, {r})"),
|
||||
};
|
||||
let t = FunctionRefTemplate;
|
||||
assert_eq!(t.render().unwrap(), "Hello, world(123, 4)!");
|
||||
}
|
||||
|
||||
|
@ -28,14 +28,22 @@ fn test_int_parser() {
|
||||
#[derive(Template)]
|
||||
#[template(source = "{{ value()? }}", ext = "txt")]
|
||||
struct FailFmt {
|
||||
value: fn() -> Result<&'static str, std::fmt::Error>,
|
||||
inner: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl FailFmt {
|
||||
fn value(&self) -> Result<&'static str, std::fmt::Error> {
|
||||
if let Some(inner) = self.inner {
|
||||
Ok(inner)
|
||||
} else {
|
||||
Err(std::fmt::Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fail_fmt() {
|
||||
let template = FailFmt {
|
||||
value: || Err(std::fmt::Error),
|
||||
};
|
||||
let template = FailFmt { inner: None };
|
||||
assert!(matches!(template.render(), Err(rinja::Error::Custom(_))));
|
||||
assert_eq!(
|
||||
format!("{}", &template.render().unwrap_err()),
|
||||
@ -43,7 +51,7 @@ fn fail_fmt() {
|
||||
);
|
||||
|
||||
let template = FailFmt {
|
||||
value: || Ok("hello world"),
|
||||
inner: Some("hello world"),
|
||||
};
|
||||
assert_eq!(template.render().unwrap(), "hello world");
|
||||
}
|
||||
@ -51,19 +59,25 @@ fn fail_fmt() {
|
||||
#[derive(Template)]
|
||||
#[template(source = "{{ value()? }}", ext = "txt")]
|
||||
struct FailStr {
|
||||
value: fn() -> Result<&'static str, &'static str>,
|
||||
value: bool,
|
||||
}
|
||||
|
||||
impl FailStr {
|
||||
fn value(&self) -> Result<&'static str, &'static str> {
|
||||
if !self.value {
|
||||
Err("FAIL")
|
||||
} else {
|
||||
Ok("hello world")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fail_str() {
|
||||
let template = FailStr {
|
||||
value: || Err("FAIL"),
|
||||
};
|
||||
let template = FailStr { value: false };
|
||||
assert!(matches!(template.render(), Err(rinja::Error::Custom(_))));
|
||||
assert_eq!(format!("{}", &template.render().unwrap_err()), "FAIL");
|
||||
|
||||
let template = FailStr {
|
||||
value: || Ok("hello world"),
|
||||
};
|
||||
let template = FailStr { value: true };
|
||||
assert_eq!(template.render().unwrap(), "hello world");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user