home ~ projects ~ socials

Call A Function On An Object From A minijinja Template

Look At This And Compare It With The Old Notes

You can refine this so it's not a point and just use something else without needing three variable examples.

```cargo
[dependencies]
minijinja = "2.7.0"
```

use minijinja::value::Enumerator;
use minijinja::value::Object;
use minijinja::{context, Environment, Error, Value};
use std::sync::Arc;

#[derive(Debug)]
struct Point(f32, f32, f32);

impl Point {
    pub fn ping(&self, args: &[Value]) -> Result<Value, Error> {
        Ok(Value::from(args[0].clone()))
    }
}

impl Object for Point {
    fn call_method(
        self: &Arc<Point>,
        _state: &minijinja::State,
        name: &str,
        args: &[Value],
    ) -> Result<Value, Error> {
        match name {
            "ping" => self.ping(args),
            _ => Ok(Value::from("")),
        }
    }

    fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
        match key.as_str()? {
            "x" => Some(Value::from(self.0)),
            "y" => Some(Value::from(self.1)),
            "z" => Some(Value::from(self.2)),
            _ => None,
        }
    }
    fn enumerate(self: &Arc<Self>) -> Enumerator {
        Enumerator::Str(&["x", "y", "z"])
    }
}

fn main() {
    let value = Value::from_object(Point(1.0, 2.5, 3.0));
    let mut env = Environment::new();
    env.add_template("basic", "{{ value.ping('foxtrot') }}").unwrap();
    let skeleton = env.get_template("basic").unwrap();
    let output = skeleton
        .render(context!(
            value => value
        ))
        .unwrap();
    dbg!(output);
}
Output:
[/Users/alan/.cargo/target/55/19854259915251/_active_nvim_run:56:5] output = "foxtrotx"

Old Notes

MiniJinja 2.x

```cargo
[dependencies]
minijinja = "2.0.1"
```

use minijinja::value::{Object, Value};
use minijinja::{context, Environment, Error};
use std::fmt::Display;
use std::sync::Arc;

fn main() {
    let mut env = Environment::new();
    env.add_template("hello", "{{ alfa_value.ping() }}")
        .unwrap();
    let tmpl = env.get_template("hello").unwrap();
    let alfa = Alfa {};
    let alfa_value = Value::from_object(alfa);
    println!(
        "{}",
        tmpl.render(context!(alfa_value => alfa_value)).unwrap()
    );
}

#[derive(Debug)]
pub struct Alfa {}

impl Object for Alfa {
    fn call_method(
       self: &Arc<Alfa>,
        _state: &minijinja::State,
        name: &str,
        _args: &[Value],
    ) -> Result<Value, Error> {
        match name {
            // NOTE: May need to do: 
            // Value::from_serializable. 
            // TODO: Look into that
            "ping" => Ok(Value::from(self.ping())),
            _ => {
                // TODO: make this an error possibly
                Ok(Value::from(""))
            }
        }
    }
}

impl Display for Alfa {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "THIS IS ALFA DISPLAY DEFAULT FORMAT")
    }
}

impl Alfa {
    fn ping(&self) -> String {
        "One ping only".to_string()
    }
}
Output:
One ping only

MiniJinja 1.x

[package]
name = "minijinji_object_method_call"
version = "0.1.0"
edition = "2021"

[dependencies]
minijinja = "1.0.7"

src/main.rs

use minijinja::value::{Object, Value};
use minijinja::{context, Environment, Error};
use std::fmt::Display;

fn main() {
    let mut env = Environment::new();
    env.add_template("hello", "{{ alfa_value.ping() }}")
        .unwrap();
    let tmpl = env.get_template("hello").unwrap();
    let alfa = Alfa {};
    let alfa_value = Value::from_object(alfa);
    println!(
        "{}",
        tmpl.render(context!(alfa_value => alfa_value)).unwrap()
    );
}

#[derive(Debug)]
pub struct Alfa {}

impl Object for Alfa {
    fn call_method(
        &self,
        _state: &minijinja::State,
        name: &str,
        _args: &[Value],
    ) -> Result<Value, Error> {
        match name {
            // NOTE: May need to do: 
            // Value::from_serializable. 
            // TODO: Look into that
            "ping" => Ok(Value::from(self.ping())),
            _ => {
                // TODO: make this an error possibly
                Ok(Value::from(""))
            }
        }
    }
}

impl Display for Alfa {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "THIS IS ALFA DISPLAY DEFAULT FORMAT")
    }
}

impl Alfa {
    fn ping(&self) -> String {
        "One ping only".to_string()
    }
}

TODO

    Switch to using Value::from_serializable as well which can be used for vecs of objects

    Update this test with args passing from call method to ping via args[0]

-- end of line --

References