1use std::ops::Not;
2use cook_with_rust_parser::*;
3
4
5pub fn recipe_to_markdown(recipe: &Recipe) -> String {
6 let mut ingredient_specifier_iter = recipe.metadata.ingredients_specifiers.iter();
7 let mut cookware_iter = recipe.metadata.cookware.iter();
8 let mut timer_iter = recipe.metadata.timer.iter();
9 let mut result_string = String::new();
10
11 if recipe.metadata.ingredients.is_empty().not() {
12 result_string += "### Ingredients\n";
13 result_string += "| Ingredient | Amount | Unit |\n";
14 result_string += "|------------|--------|------|\n";
15
16 let ingredients = recipe.metadata.ingredients.values();
17 ingredients.for_each(|e| {
18 let amount = match &e.amount {
19 Some(d) => {
20 match d {
21 Amount::Multi(dd) => {
22 format!("servings * {}", dd)
23 }
24 Amount::Servings(dd) => {
25 let mut servings = String::new();
26 dd.iter().for_each(|a| {
27 servings.push_str(&a.to_string());
28 servings.push('|');
29 });
30 servings.pop();
31 servings
32 }
33 Amount::Single(dd) => {
34 dd.to_string()
35 }
36 }
37 },
38 None => "-".to_string(),
39 };
40 let unit = match &e.unit {
41 None => "-".to_string(),
42 Some(u) => u.to_string(),
43 };
44 let line = format!("| {} | {} | {} |\n", e.name, amount, unit);
45 result_string += &line;
46 });
47 result_string += "\n"
48 }
49
50 if recipe.metadata.cookware.is_empty().not() {
51 result_string += "\n### Cookware:\n";
52 recipe.metadata.cookware.iter().for_each(|cookw| {
53 result_string += format!("* {}\n", cookw).as_str();
54 });
55 }
56
57 recipe.instruction.chars().for_each(|char| {
58 if char == '@' {
59 let insert_ingredient = ingredient_specifier_iter.next().unwrap();
60 let ingredient_referenced = recipe.metadata.ingredients.get(&insert_ingredient.ingredient).unwrap();
61 let ingredient_name = &ingredient_referenced.name;
62 let ingredient_unit = match &ingredient_referenced.unit {
63 None => "".to_string(),
64 Some(d) => {
65 let mut res = String::from(' ');
66 res.push_str(d.as_str());
67 res
68 },
69 };
70 let ingredient_amount = match &insert_ingredient.amount_in_step {
71 Amount::Multi(d) => {
72 format!(" *{}", d)
73 }
74 Amount::Servings(dd) => {
75 let mut servings = String::new();
76 servings.push(' ');
77 dd.iter().for_each(|a| {
78 servings.push_str(&a.to_string());
79 servings.push('|');
80 });
81 servings.pop();
82 servings
84 }
85 Amount::Single(d) => {
86 let mut res = String::from(' ');
87 res.push_str(d.to_string().as_str());
88 res
90 }
91 };
92 let insert_string = format!("__{}{}{}__", ingredient_name, ingredient_amount, ingredient_unit);
93 result_string += &insert_string;
94 } else if char == '#' {
95 result_string.push_str("_");
96 result_string.push_str(cookware_iter.next().unwrap());
97 result_string.push_str("_");
98 } else if char == '~' {
99 let timer = timer_iter.next().unwrap();
100 result_string.push_str("__");
101 result_string.push_str(&timer.amount.to_string());
102 result_string.push(' ');
103 result_string.push_str(&timer.unit);
104 result_string.push_str("__");
105 } else {
106 result_string.push(char);
107 }
108 });
109
110 result_string
111}
112
113#[cfg(test)]
114mod tests {
115 use std::fs::read_to_string;
116 use cook_with_rust_parser::parse;
117 use crate::recipe_to_markdown;
118
119 #[test]
120 fn it_works() {
121 let inp = read_to_string("../spec/examples/Coffee Souffle.cook").unwrap();
122 let recipe = parse(&inp).unwrap();
123
124 let _result = recipe_to_markdown(&recipe);
125
126 }
128}