Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions src/scale.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ impl ScaleTarget {
/// Creates a new [`ScaleTarget`].
///
/// - `factor` is the multiplier to scale the recipe by.
/// Invalid parameters don't error here, but may do so in the
/// scaling process.
/// Invalid parameters don't error here, but may do so in the
/// scaling process.
fn new(factor: f64) -> Self {
ScaleTarget { factor }
}
Expand Down Expand Up @@ -150,8 +150,25 @@ impl ScalableRecipe {
timers: timer_outcomes,
};

// Update metadata with new servings
let mut metadata = self.metadata;
if let Servings(Some(servings)) = &self.data {
if let Some(base_servings) = servings.first() {
let new_servings = (*base_servings as f64 * factor).round() as u32;
if metadata.get(crate::metadata::StdKey::Servings).is_some() {
// Update existing servings value
if let Some(servings_value) =
metadata.get_mut(crate::metadata::StdKey::Servings)
{
*servings_value =
serde_yaml::Value::Number(serde_yaml::Number::from(new_servings));
}
}
}
}

ScaledRecipe {
metadata: self.metadata,
metadata,
sections: self.sections,
ingredients,
cookware,
Expand Down
93 changes: 93 additions & 0 deletions tests/scale.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use cooklang::{Converter, CooklangParser, Extensions};

#[test]
fn test_scale_updates_servings_metadata() {
let input = r#">> servings: 4

@flour{200%g}
@eggs{2}
Mix and bake."#;

let parser = CooklangParser::new(Extensions::all(), Converter::default());
let recipe = parser.parse(input).unwrap_output();

// Check original servings
assert_eq!(recipe.servings(), Some(&[4][..]));
let orig_servings_value = recipe
.metadata
.get(cooklang::metadata::StdKey::Servings)
.unwrap();
assert_eq!(orig_servings_value.as_str(), Some("4"));

// Scale to 8 servings (2x)
let scaled = recipe.scale_to_servings(8, &Converter::default());

// Check that servings in metadata were updated
let scaled_servings_value = scaled
.metadata
.get(cooklang::metadata::StdKey::Servings)
.unwrap();
assert_eq!(scaled_servings_value.as_u64(), Some(8));
}

#[test]
fn test_scale_by_factor_updates_servings_metadata() {
let input = r#">> servings: 2

@butter{100%g}
@sugar{50%g}"#;

let parser = CooklangParser::new(Extensions::all(), Converter::default());
let recipe = parser.parse(input).unwrap_output();

// Scale by factor of 3
let scaled = recipe.scale(3.0, &Converter::default());

// Check that servings in metadata were updated (2 * 3 = 6)
let scaled_servings_value = scaled
.metadata
.get(cooklang::metadata::StdKey::Servings)
.unwrap();
assert_eq!(scaled_servings_value.as_u64(), Some(6));
}

#[test]
fn test_scale_without_servings_metadata() {
// Recipe without servings metadata
let input = r#"@flour{200%g}
@eggs{2}"#;

let parser = CooklangParser::new(Extensions::all(), Converter::default());
let recipe = parser.parse(input).unwrap_output();

// Should not have servings
assert_eq!(recipe.servings(), None);

// Scale by factor of 2
let scaled = recipe.scale(2.0, &Converter::default());

// Should still not have servings in metadata
assert!(scaled
.metadata
.get(cooklang::metadata::StdKey::Servings)
.is_none());
}

#[test]
fn test_scale_with_fractional_servings() {
let input = r#">> servings: 3

@milk{300%ml}"#;

let parser = CooklangParser::new(Extensions::all(), Converter::default());
let recipe = parser.parse(input).unwrap_output();

// Scale by factor that results in fractional servings (3 * 1.5 = 4.5, should round to 5)
let scaled = recipe.scale(1.5, &Converter::default());

let scaled_servings_value = scaled
.metadata
.get(cooklang::metadata::StdKey::Servings)
.unwrap();
assert_eq!(scaled_servings_value.as_u64(), Some(5));
}