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
14 changes: 2 additions & 12 deletions src/recipe/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
// SOFTWARE.

use anyhow::{Context as _, Result};
use clap::{Args, CommandFactory, ValueEnum};
use clap::{Args, ValueEnum};
use std::io::Read;

use camino::Utf8PathBuf;
Expand Down Expand Up @@ -99,17 +99,7 @@ pub fn run(ctx: &Context, args: ReadArgs) -> Result<()> {

let (recipe, title) = if let Some(query) = args.input.recipe {
let (name, scaling_factor) = split_recipe_name_and_scaling_factor(query.as_str())
.map(|(name, scaling_factor)| {
let target = scaling_factor.parse::<f64>().unwrap_or_else(|err| {
let mut cmd = crate::args::CliArgs::command();
cmd.error(
clap::error::ErrorKind::InvalidValue,
format!("Invalid scaling target for '{name}': {err}. Use a number value after : to specify a scaling factor."),
)
.exit()
});
(name, Some(target))
})
.map(|(name, factor)| (name, Some(factor)))
.unwrap_or((query.as_str(), None));

if let Some(scaling_factor) = scaling_factor {
Expand Down
17 changes: 3 additions & 14 deletions src/report.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::util::split_recipe_name_and_scaling_factor;
use anyhow::{Context, Result};
use camino::Utf8PathBuf;
use clap::{CommandFactory, Parser};
use clap::Parser;
use cooklang_reports::{config::Config, render_template_with_config};
use std::{fs, path::PathBuf};
use tracing::warn;
Expand Down Expand Up @@ -66,19 +66,8 @@ pub fn run(ctx: &crate::Context, args: ReportArgs) -> Result<()> {
warn!("⚠️ The report command is a prototype feature and will change in future versions.");

// Split recipe name and scaling factor
let (recipe_name, scaling_factor) = split_recipe_name_and_scaling_factor(&args.recipe)
.map(|(name, factor)| {
let scale = factor.parse::<f64>().unwrap_or_else(|err| {
let mut cmd = crate::args::CliArgs::command();
cmd.error(
clap::error::ErrorKind::InvalidValue,
format!("Invalid scaling factor for '{name}': {err}"),
)
.exit()
});
(name, scale)
})
.unwrap_or((&args.recipe, 1.0));
let (recipe_name, scaling_factor) =
split_recipe_name_and_scaling_factor(&args.recipe).unwrap_or((&args.recipe, 1.0));

// Read the recipe file
let recipe = fs::read_to_string(recipe_name)
Expand Down
65 changes: 49 additions & 16 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ pub mod format;

use anyhow::{Context as _, Result};
use camino::{Utf8Path, Utf8PathBuf};
use clap::CommandFactory;
use cooklang::{
ingredient_list::IngredientList, quantity::Value, Converter, CooklangParser, Extensions, Recipe,
};
Expand Down Expand Up @@ -113,8 +112,10 @@ where
Ok(())
}

pub fn split_recipe_name_and_scaling_factor(query: &str) -> Option<(&str, &str)> {
query.trim().rsplit_once(RECIPE_SCALING_DELIMITER)
pub fn split_recipe_name_and_scaling_factor(query: &str) -> Option<(&str, f64)> {
let (name, factor) = query.trim().rsplit_once(RECIPE_SCALING_DELIMITER)?;
let factor = factor.parse::<f64>().ok()?;
Some((name, factor))
}

/// Resolves a path to an absolute path. If the input path is already absolute,
Expand Down Expand Up @@ -171,19 +172,8 @@ pub fn extract_ingredients(
seen.insert(entry.to_string(), seen.len());

// split into name and servings
let (name, scaling_factor) = split_recipe_name_and_scaling_factor(entry)
.map(|(name, scaling_factor)| {
let target = scaling_factor.parse::<f64>().unwrap_or_else(|err| {
let mut cmd = crate::args::CliArgs::command();
cmd.error(
clap::error::ErrorKind::InvalidValue,
format!("Invalid scaling target for '{name}': {err}"),
)
.exit()
});
(name, target)
})
.unwrap_or((entry, 1.0));
let (name, scaling_factor) =
split_recipe_name_and_scaling_factor(entry).unwrap_or((entry, 1.0));

let recipe_entry =
get_recipe(base_path, name).with_context(|| format!("Failed to find recipe '{name}'"))?;
Expand Down Expand Up @@ -400,3 +390,46 @@ pub fn get_recipe(base_path: &Utf8PathBuf, name: &str) -> Result<RecipeEntry> {
clean_name.into(),
)?)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn splits_recipe_with_numeric_scaling_factor() {
assert_eq!(
split_recipe_name_and_scaling_factor("recipe.cook:2"),
Some(("recipe.cook", 2.0))
);
}

#[test]
fn splits_recipe_with_decimal_scaling_factor() {
assert_eq!(
split_recipe_name_and_scaling_factor("recipe.cook:1.5"),
Some(("recipe.cook", 1.5))
);
}

#[test]
fn returns_none_when_no_colon() {
assert_eq!(split_recipe_name_and_scaling_factor("recipe.cook"), None);
}

#[test]
fn returns_none_for_windows_absolute_path() {
// Regression for https://github.com/cooklang/cookcli/issues/335
assert_eq!(
split_recipe_name_and_scaling_factor(r"C:\test\recipe.cook"),
None
);
}

#[test]
fn returns_none_when_right_side_is_not_numeric() {
assert_eq!(
split_recipe_name_and_scaling_factor("recipe.cook:abc"),
None
);
}
}
Loading