Skip to content

Commit

Permalink
refactor: yeasts to be found with function
Browse files Browse the repository at this point in the history
Relates to #111
  • Loading branch information
drodil committed Oct 1, 2021
1 parent ed52b84 commit 8fefb9b
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 26 deletions.
59 changes: 47 additions & 12 deletions rustybeer-cli/src/commands/yeast.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use rustybeer::yeasts::YEASTS;
use rustybeer::conversions::TemperatureParser;
use rustybeer::measurements::Temperature;
use rustybeer::yeasts::{get_yeasts, Criteria, Yeast};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
Expand All @@ -8,19 +10,52 @@ pub struct YeastOptions {
#[structopt(short, long)]
/// Search by yeast name
name: Option<String>,
#[structopt(short, long)]
/// Search by yeast producer
company: Option<String>,
#[structopt(short, long)]
/// Search by yeast attenuation
attenuation: Option<u8>,
#[structopt(short, long, parse(try_from_str = TemperatureParser::parse))]
/// Search by yeast optimal temperature
temperature: Option<Temperature>,
}

pub fn search_and_print(opt: YeastOptions) {
if let Some(name) = opt.name {
let criteria = name.to_lowercase();
for yeast in YEASTS.iter() {
if yeast.name.to_lowercase().contains(&criteria) {
println!("{:?}", yeast);
}
}
} else {
for yeast in YEASTS.iter() {
println!("{:?}", yeast);
}
let criteria = Criteria {
name: opt.name,
company: opt.company,
attenuation: opt.attenuation,
temperature: opt.temperature,
};

let resp: Vec<&Yeast> = get_yeasts(Some(criteria));

if resp.is_empty() {
println!("Could not find any yeasts matching criteria");
return;
}

println!("Found the following yeasts with criteria:");
for x in &resp {
println!("---------------------");
println!("{}", x.name);
println!("{}\n", x.company);
println!(
"Attenuation: {}-{}",
x.min_attenuation.unwrap_or(0),
x.max_attenuation.unwrap_or(0)
);
println!(
"Temperature: {}-{}",
x.min_temp
.unwrap_or(Temperature::from_celsius(0.0))
.as_celsius(),
x.max_temp
.unwrap_or(Temperature::from_celsius(0.0))
.as_celsius()
);
println!("Alcohol tolerance: {}", x.alc_tolerance.unwrap_or(0));
}
println!("---------------------");
}
16 changes: 12 additions & 4 deletions rustybeer-server/src/handlers/yeasts.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rustybeer::conversions::TemperatureParser;
use rustybeer::conversions::ToMap;
pub use rustybeer::yeasts::{Criteria, Yeast, YEASTS};
pub use rustybeer::yeasts::{get_yeasts, Criteria, Yeast};
use rweb::*;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
Expand Down Expand Up @@ -75,16 +76,23 @@ impl YeastResponse {
)]
pub fn search(q: Query<YeastQuery>) -> Json<Vec<YeastResponse>> {
let query = q.into_inner();
let mut temp = None;
if query.temperature.is_some() {
temp = match TemperatureParser::parse(&query.temperature.unwrap()) {
Ok(temperature) => Some(temperature),
Err(_) => None,
};
}

let criteria = Criteria {
name: query.name,
company: query.company,
attenuation: query.attenuation,
temperature: query.temperature,
temperature: temp,
};

let resp: Vec<YeastResponse> = YEASTS
let resp: Vec<YeastResponse> = get_yeasts(Some(criteria))
.iter()
.filter(|yeast| criteria.matches(yeast))
.map(|yeast| YeastResponse::from_yeast(&yeast))
.collect();

Expand Down
23 changes: 13 additions & 10 deletions rustybeer/src/yeasts.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::conversions::TemperatureParser;
use crate::strings::contains_case_insensitive;
/// Yeast list curated from https://www.brewersfriend.com/yeast/
use measurements::temperature::Temperature;
Expand Down Expand Up @@ -73,13 +72,17 @@ where
}

static YEASTS_JSON: &str = include_str!("json/yeasts.json");

/// All available yeasts.
///
/// Data will be loaded from JSON on the first use.
pub static YEASTS: Lazy<Vec<Yeast>> =
static YEASTS: Lazy<Vec<Yeast>> =
Lazy::new(|| serde_json::from_str(YEASTS_JSON).expect("yeasts data could not be deserialised"));

pub fn get_yeasts(criteria: Option<Criteria>) -> Vec<&'static Yeast> {
let crit = criteria.unwrap_or_default();
YEASTS.iter().filter(|yeast| crit.matches(yeast)).collect()
}

/// Criteria for selecting a yeast.
///
/// If an attribute is `None`, it is ignored.
Expand All @@ -88,7 +91,7 @@ pub struct Criteria {
pub company: Option<String>,
pub name: Option<String>,
pub attenuation: Option<u8>,
pub temperature: Option<String>,
pub temperature: Option<Temperature>,
}

impl Criteria {
Expand All @@ -114,11 +117,11 @@ impl Criteria {
}
}

if let Some(temperature) = &self.temperature {
if let Ok(temp) = TemperatureParser::parse(temperature) {
if temp < yeast.min_temp.unwrap_or(temp) || temp > yeast.max_temp.unwrap_or(temp) {
return false;
}
if let Some(temperature) = self.temperature {
if temperature < yeast.min_temp.unwrap_or(temperature)
|| temperature > yeast.max_temp.unwrap_or(temperature)
{
return false;
}
}

Expand Down Expand Up @@ -164,7 +167,7 @@ mod tests {
// Inclusive values match
criteria.attenuation = Some(7);
assert!(criteria.matches(&TEST_YEAST));
criteria.temperature = Some("20C".to_owned());
criteria.temperature = Some(Temperature::from_celsius(20.0).to_owned());
assert!(criteria.matches(&TEST_YEAST));
criteria.company = Some("yeast".to_owned());
assert!(criteria.matches(&TEST_YEAST));
Expand Down

0 comments on commit 8fefb9b

Please sign in to comment.