use super::Quantity;
use serde::Serialize;
use std::fmt::Display;
#[derive(Clone, Debug, Serialize)]
pub struct Ingredient(cooklang::Ingredient);
impl From<cooklang::Ingredient> for Ingredient {
fn from(ingredient: cooklang::Ingredient) -> Self {
Self(ingredient)
}
}
impl From<Ingredient> for minijinja::Value {
fn from(value: Ingredient) -> Self {
Self::from_object(value)
}
}
impl Display for Ingredient {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.0.quantity {
Some(quantity) => write!(f, "{quantity} {}", self.0.display_name()),
None => write!(f, "{}", self.0.display_name()),
}
}
}
impl minijinja::value::Object for Ingredient {
fn repr(self: &std::sync::Arc<Self>) -> minijinja::value::ObjectRepr {
minijinja::value::ObjectRepr::Plain
}
fn get_value(self: &std::sync::Arc<Self>, key: &minijinja::Value) -> Option<minijinja::Value> {
match key.as_str()? {
"name" => Some(minijinja::Value::from(&self.0.name)),
"note" => self.0.note.as_ref().map(minijinja::Value::from),
"alias" => self.0.alias.as_ref().map(minijinja::Value::from),
"quantity" => self
.0
.quantity
.clone()
.map(Quantity::from)
.map(minijinja::Value::from),
"reference" => Some(minijinja::Value::from(self.0.reference.is_some())),
"reference_path" => self
.0
.reference
.as_ref()
.map(|r| minijinja::Value::from(r.path("/"))),
_ => None,
}
}
fn render(self: &std::sync::Arc<Self>, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
where
Self: Sized + 'static,
{
self.fmt(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::model::tests::get_recipe_and_env;
use minijinja::{Value, context};
use test_case::test_case;
#[test_case("Measure @olive oil{} into #frying pan{}.", "{{ ingredient }}", "olive oil"; "just name")]
#[test_case("Measure @olive oil{1} into #frying pan{}.", "{{ ingredient }}", "1 olive oil"; "name and no unit quantity")]
#[test_case("Measure @olive oil{1%tbsp} into #frying pan{}.", "{{ ingredient }}", "1 tbsp olive oil"; "name and quantity")]
fn ingredient(recipe: &str, template: &str, result: &str) {
let (recipe, env) = get_recipe_and_env(recipe, template);
let context = context! {
ingredient => Value::from(Ingredient(recipe.ingredients[0].clone()))
};
let template = env.get_template("test").unwrap();
assert_eq!(result, template.render(context).unwrap());
}
}