mirror of
https://github.com/zaphar/kitchen.git
synced 2025-07-21 19:29:49 -04:00
Have a packaging unit for measures
This commit is contained in:
parent
94e1987f09
commit
9022503e76
@ -156,16 +156,25 @@ impl IngredientAccumulator {
|
||||
set.insert(recipe_title.clone());
|
||||
self.inner.insert(key, (i.clone(), set));
|
||||
} else {
|
||||
let amt = match (self.inner[&key].0.amt, i.amt) {
|
||||
(Volume(rvm), Volume(lvm)) => Volume(lvm + rvm),
|
||||
(Count(lqty), Count(rqty)) => Count(lqty + rqty),
|
||||
(Weight(lqty), Weight(rqty)) => Weight(lqty + rqty),
|
||||
let amts = match (&self.inner[&key].0.amt, &i.amt) {
|
||||
(Volume(rvm), Volume(lvm)) => vec![Volume(lvm + rvm)],
|
||||
(Count(lqty), Count(rqty)) => vec![Count(lqty + rqty)],
|
||||
(Weight(lqty), Weight(rqty)) => vec![Weight(lqty + rqty)],
|
||||
(Package(lnm, lqty), Package(rnm, rqty)) => {
|
||||
if lnm == rnm {
|
||||
vec![Package(lnm.clone(), lqty + rqty)]
|
||||
} else {
|
||||
vec![Package(lnm.clone(), lqty.clone()), Package(rnm.clone(), rqty.clone())]
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.inner.get_mut(&key).map(|(i, set)| {
|
||||
i.amt = amt;
|
||||
set.insert(recipe_title.clone());
|
||||
});
|
||||
for amt in amts {
|
||||
self.inner.get_mut(&key).map(|(i, set)| {
|
||||
i.amt = amt;
|
||||
set.insert(recipe_title.clone());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -334,7 +334,14 @@ make_fn!(unit<StrIter, String>,
|
||||
text_token!("kg"),
|
||||
text_token!("grams"),
|
||||
text_token!("gram"),
|
||||
text_token!("g")),
|
||||
text_token!("g"),
|
||||
text_token!("pkg"),
|
||||
text_token!("package"),
|
||||
text_token!("bottle"),
|
||||
text_token!("bot"),
|
||||
text_token!("bag"),
|
||||
text_token!("can")
|
||||
),
|
||||
_ => ws,
|
||||
(u.to_lowercase().to_singular())
|
||||
)
|
||||
@ -393,6 +400,7 @@ pub fn measure(i: StrIter) -> abortable_parser::Result<StrIter, Measure> {
|
||||
"oz" => Weight(Oz(qty)),
|
||||
"kg" | "kilogram" => Weight(Kilogram(qty)),
|
||||
"g" | "gram" => Weight(Gram(qty)),
|
||||
"pkg" | "package" | "can" | "bag" | "bottle" | "bot" => Measure::pkg(s, qty),
|
||||
_u => {
|
||||
eprintln!("Invalid unit: {}", _u);
|
||||
unreachable!()
|
||||
@ -411,6 +419,8 @@ pub fn measure(i: StrIter) -> abortable_parser::Result<StrIter, Measure> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jwall): I think this is a mistake. We should rethink what noralizing means or we should
|
||||
// remove it.
|
||||
pub fn normalize_name(name: &str) -> String {
|
||||
let parts: Vec<&str> = name.split_whitespace().collect();
|
||||
if parts.len() >= 2 {
|
||||
|
@ -235,32 +235,30 @@ fn test_ingredient_name_parse() {
|
||||
#[test]
|
||||
fn test_ingredient_parse() {
|
||||
for (i, expected) in vec![
|
||||
//(
|
||||
// "1 cup flour ",
|
||||
// Ingredient::new("flour", None, Volume(Cup(Quantity::Whole(1))), ""),
|
||||
//),
|
||||
//(
|
||||
// "\t1 cup flour ",
|
||||
// Ingredient::new("flour", None, Volume(Cup(Quantity::Whole(1))), ""),
|
||||
//),
|
||||
//(
|
||||
// "1 cup apple (chopped)",
|
||||
// Ingredient::new(
|
||||
// "apple",
|
||||
// Some("chopped".to_owned()),
|
||||
// Volume(Cup(Quantity::Whole(1))),
|
||||
// "",
|
||||
// ),
|
||||
//),
|
||||
//(
|
||||
// "1 cup apple (chopped) ",
|
||||
// Ingredient::new(
|
||||
// "apple",
|
||||
// Some("chopped".to_owned()),
|
||||
// Volume(Cup(Quantity::Whole(1))),
|
||||
// "",
|
||||
// ),
|
||||
//),
|
||||
(
|
||||
"1 cup flour ",
|
||||
Ingredient::new("flour", None, Volume(Cup(Quantity::Whole(1)))),
|
||||
),
|
||||
(
|
||||
"\t1 cup flour ",
|
||||
Ingredient::new("flour", None, Volume(Cup(Quantity::Whole(1)))),
|
||||
),
|
||||
(
|
||||
"1 cup apple (chopped)",
|
||||
Ingredient::new(
|
||||
"apple",
|
||||
Some("chopped".to_owned()),
|
||||
Volume(Cup(Quantity::Whole(1))),
|
||||
),
|
||||
),
|
||||
(
|
||||
"1 cup apple (chopped) ",
|
||||
Ingredient::new(
|
||||
"apple",
|
||||
Some("chopped".to_owned()),
|
||||
Volume(Cup(Quantity::Whole(1))),
|
||||
),
|
||||
),
|
||||
(
|
||||
"1 green bell pepper (chopped) ",
|
||||
Ingredient::new(
|
||||
@ -269,6 +267,46 @@ fn test_ingredient_parse() {
|
||||
Count(Quantity::Whole(1)),
|
||||
),
|
||||
),
|
||||
(
|
||||
"1 pkg green onion",
|
||||
Ingredient::new(
|
||||
"green onion",
|
||||
None,
|
||||
Package("pkg".into(), Quantity::Whole(1)),
|
||||
),
|
||||
),
|
||||
(
|
||||
"1 bottle green onion",
|
||||
Ingredient::new(
|
||||
"green onion",
|
||||
None,
|
||||
Package("bottle".into(), Quantity::Whole(1)),
|
||||
),
|
||||
),
|
||||
(
|
||||
"1 bot green onion",
|
||||
Ingredient::new(
|
||||
"green onion",
|
||||
None,
|
||||
Package("bot".into(), Quantity::Whole(1)),
|
||||
),
|
||||
),
|
||||
(
|
||||
"1 bag green onion",
|
||||
Ingredient::new(
|
||||
"green onion",
|
||||
None,
|
||||
Package("bag".into(), Quantity::Whole(1)),
|
||||
),
|
||||
),
|
||||
(
|
||||
"1 can baked beans",
|
||||
Ingredient::new(
|
||||
"baked bean",
|
||||
None,
|
||||
Package("can".into(), Quantity::Whole(1)),
|
||||
),
|
||||
),
|
||||
] {
|
||||
match parse::ingredient(StrIter::new(i)) {
|
||||
ParseResult::Complete(_, ing) => assert_eq!(ing, expected),
|
||||
|
@ -21,7 +21,7 @@ use std::{
|
||||
cmp::{Ordering, PartialEq, PartialOrd},
|
||||
convert::TryFrom,
|
||||
fmt::Display,
|
||||
ops::{Add, Div, Mul, Sub},
|
||||
ops::{Add, Div, Mul, Sub}, rc::Rc,
|
||||
};
|
||||
|
||||
use num_rational::Ratio;
|
||||
@ -179,6 +179,20 @@ impl VolumeMeasure {
|
||||
|
||||
macro_rules! volume_op {
|
||||
($trait:ident, $method:ident) => {
|
||||
impl $trait for &VolumeMeasure {
|
||||
type Output = VolumeMeasure;
|
||||
|
||||
fn $method(self, lhs: Self) -> Self::Output {
|
||||
let (l, r) = (self.get_ml(), lhs.get_ml());
|
||||
let result = ML($trait::$method(l, r));
|
||||
if self.metric() {
|
||||
result.normalize()
|
||||
} else {
|
||||
result.into_tsp().normalize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $trait for VolumeMeasure {
|
||||
type Output = Self;
|
||||
|
||||
@ -293,6 +307,20 @@ impl WeightMeasure {
|
||||
|
||||
macro_rules! weight_op {
|
||||
($trait:ident, $method:ident) => {
|
||||
impl $trait for &WeightMeasure {
|
||||
type Output = WeightMeasure;
|
||||
|
||||
fn $method(self, lhs: Self) -> Self::Output {
|
||||
let (l, r) = (self.get_grams(), lhs.get_grams());
|
||||
let result = WeightMeasure::Gram($trait::$method(l, r));
|
||||
if self.metric() {
|
||||
result.normalize()
|
||||
} else {
|
||||
result.into_oz().normalize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $trait for WeightMeasure {
|
||||
type Output = Self;
|
||||
|
||||
@ -335,18 +363,19 @@ impl Display for WeightMeasure {
|
||||
|
||||
use WeightMeasure::{Gram, Kilogram, Oz, Pound};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
|
||||
/// Measurements in a Recipe with associated units for them.
|
||||
pub enum Measure {
|
||||
/// Volume measurements as meter cubed base unit
|
||||
Volume(VolumeMeasure),
|
||||
/// Simple count of items
|
||||
Count(Quantity),
|
||||
Package(Rc<str>, Quantity),
|
||||
/// Weight measure as Grams base unit
|
||||
Weight(WeightMeasure),
|
||||
}
|
||||
|
||||
use Measure::{Count, Volume, Weight};
|
||||
use Measure::{Count, Volume, Weight, Package};
|
||||
|
||||
impl Measure {
|
||||
pub fn tsp(qty: Quantity) -> Self {
|
||||
@ -407,11 +436,16 @@ impl Measure {
|
||||
Weight(Oz(qty))
|
||||
}
|
||||
|
||||
pub fn pkg<S: Into<Rc<str>>>(name: S, qty: Quantity) -> Self {
|
||||
Package(name.into(), qty)
|
||||
}
|
||||
|
||||
pub fn measure_type(&self) -> String {
|
||||
match self {
|
||||
Volume(_) => "Volume",
|
||||
Count(_) => "Count",
|
||||
Weight(_) => "Weight",
|
||||
Package(_, _) => "Package",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
@ -421,6 +455,7 @@ impl Measure {
|
||||
Volume(vm) => vm.plural(),
|
||||
Count(qty) => qty.plural(),
|
||||
Weight(wm) => wm.plural(),
|
||||
Package(_, qty) => qty.plural(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,6 +464,7 @@ impl Measure {
|
||||
Volume(vm) => Volume(vm.normalize()),
|
||||
Count(qty) => Count(qty.clone()),
|
||||
Weight(wm) => Weight(wm.normalize()),
|
||||
Package(nm, qty) => Package(nm.clone(), qty.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -439,6 +475,7 @@ impl Display for Measure {
|
||||
Volume(vm) => write!(w, "{}", vm),
|
||||
Count(qty) => write!(w, "{}", qty),
|
||||
Weight(wm) => write!(w, "{}", wm),
|
||||
Package(nm, qty) => write!(w, "{} {}", qty, nm),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -533,6 +570,22 @@ impl TryFrom<f32> for Quantity {
|
||||
|
||||
macro_rules! quantity_op {
|
||||
($trait:ident, $method:ident) => {
|
||||
impl $trait for &Quantity {
|
||||
type Output = Quantity;
|
||||
|
||||
fn $method(self, lhs: Self) -> Self::Output {
|
||||
match (self, lhs) {
|
||||
(Whole(rhs), Whole(lhs)) => Frac($trait::$method(
|
||||
Ratio::from_integer(*rhs),
|
||||
Ratio::from_integer(*lhs),
|
||||
)),
|
||||
(Frac(rhs), Frac(lhs)) => Frac($trait::$method(rhs, lhs)),
|
||||
(Whole(rhs), Frac(lhs)) => Frac($trait::$method(Ratio::from_integer(*rhs), lhs)),
|
||||
(Frac(rhs), Whole(lhs)) => Frac($trait::$method(rhs, Ratio::from_integer(*lhs))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $trait for Quantity {
|
||||
type Output = Self;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user