Skip to content

Commit 37fccf7

Browse files
authored
Merge pull request #34 from cooklang/feat/recipe-reference
Feat/recipe reference
2 parents d7491bb + 11792f0 commit 37fccf7

File tree

3 files changed

+98
-1
lines changed

3 files changed

+98
-1
lines changed

src/analysis/event_consumer.rs

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,13 +577,19 @@ impl<'i> RecipeCollector<'i, '_> {
577577
let located_ingredient = ingredient.clone();
578578
let (ingredient, location) = ingredient.take_pair();
579579

580-
let name = ingredient.name.text_trimmed();
580+
let mut name = ingredient.name.text_trimmed();
581+
let reference = parse_reference(&name);
582+
583+
if let Some(reference) = &reference {
584+
name = reference.name.clone().into();
585+
}
581586

582587
let mut new_igr = Ingredient {
583588
name: name.into_owned(),
584589
alias: ingredient.alias.map(|t| t.text_trimmed().into_owned()),
585590
quantity: ingredient.quantity.clone().map(|q| self.quantity(q, true)),
586591
note: ingredient.note.map(|n| n.text_trimmed().into_owned()),
592+
reference,
587593
modifiers: ingredient.modifiers.into_inner(),
588594
relation: IngredientRelation::definition(
589595
Vec::new(),
@@ -1488,3 +1494,84 @@ fn yaml_find_key_position(text: &str, key: &str) -> Option<usize> {
14881494
}
14891495
None
14901496
}
1497+
1498+
fn parse_reference(name: &str) -> Option<RecipeReference> {
1499+
if name.starts_with("./") || name.starts_with("../") || name.starts_with(".\\") || name.starts_with("..\\") {
1500+
let path = name.replace('\\', "/");
1501+
let mut components: Vec<String> = path.split('/').map(String::from).skip(1).collect();
1502+
let file_stem = components.pop().unwrap();
1503+
Some(RecipeReference {
1504+
components,
1505+
name: file_stem.into()
1506+
})
1507+
} else {
1508+
None
1509+
}
1510+
}
1511+
1512+
#[cfg(test)]
1513+
mod tests {
1514+
use super::*;
1515+
1516+
#[test]
1517+
fn test_parse_reference() {
1518+
// Test Unix-style paths
1519+
assert_eq!(
1520+
parse_reference("./pasta/spaghetti"),
1521+
Some(RecipeReference {
1522+
components: vec!["pasta".to_string()],
1523+
name: "spaghetti".into()
1524+
})
1525+
);
1526+
1527+
assert_eq!(
1528+
parse_reference("../sauces/tomato"),
1529+
Some(RecipeReference {
1530+
components: vec!["sauces".to_string()],
1531+
name: "tomato".into()
1532+
})
1533+
);
1534+
1535+
// Test Windows-style paths
1536+
assert_eq!(
1537+
parse_reference(r#".\pasta\spaghetti"#),
1538+
Some(RecipeReference {
1539+
components: vec!["pasta".to_string()],
1540+
name: "spaghetti".into()
1541+
})
1542+
);
1543+
1544+
assert_eq!(
1545+
parse_reference(r#"..\sauces\tomato"#),
1546+
Some(RecipeReference {
1547+
components: vec!["sauces".to_string()],
1548+
name: "tomato".into()
1549+
})
1550+
);
1551+
1552+
// Test deeper paths
1553+
assert_eq!(
1554+
parse_reference("./recipes/italian/pasta/spaghetti"),
1555+
Some(RecipeReference {
1556+
components: vec!["recipes".to_string(), "italian".to_string(), "pasta".to_string()],
1557+
name: "spaghetti".into()
1558+
})
1559+
);
1560+
1561+
// Test paths with no components (just file)
1562+
assert_eq!(
1563+
parse_reference("./spaghetti"),
1564+
Some(RecipeReference {
1565+
components: vec![],
1566+
name: "spaghetti".into()
1567+
})
1568+
);
1569+
1570+
// Test non-path names (should return None)
1571+
assert_eq!(parse_reference("spaghetti"), None);
1572+
assert_eq!(parse_reference("pasta/spaghetti"), None);
1573+
assert_eq!(parse_reference("pasta\\spaghetti"), None);
1574+
assert_eq!(parse_reference("/pasta/spaghetti"), None);
1575+
assert_eq!(parse_reference("\\pasta\\spaghetti"), None);
1576+
}
1577+
}

src/model.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,12 @@ pub enum Item {
163163
},
164164
}
165165

166+
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
167+
pub struct RecipeReference {
168+
pub name: String,
169+
pub components: Vec<String>
170+
}
171+
166172
/// A recipe ingredient
167173
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
168174
pub struct Ingredient<V: QuantityValue = Value> {
@@ -176,6 +182,8 @@ pub struct Ingredient<V: QuantityValue = Value> {
176182
pub quantity: Option<Quantity<V>>,
177183
/// Note
178184
pub note: Option<String>,
185+
/// Recipe reference
186+
pub reference: Option<RecipeReference>,
179187
/// How the cookware is related to others
180188
pub relation: IngredientRelation,
181189
pub(crate) modifiers: Modifiers,

src/scale.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ impl Scale for Ingredient<ScalableValue> {
273273
alias: self.alias,
274274
quantity,
275275
note: self.note,
276+
reference: self.reference,
276277
relation: self.relation,
277278
modifiers: self.modifiers,
278279
};
@@ -285,6 +286,7 @@ impl Scale for Ingredient<ScalableValue> {
285286
alias: self.alias,
286287
quantity: self.quantity.map(Quantity::default_scale),
287288
note: self.note,
289+
reference: self.reference,
288290
relation: self.relation,
289291
modifiers: self.modifiers,
290292
}

0 commit comments

Comments
 (0)