Skip to content

Commit

Permalink
Target parsed directly from clap
Browse files Browse the repository at this point in the history
clap can do some clever conversion using the `From`
and `Into` traits. I'm using this to simplify slightly
the parsing of `Target`.
  • Loading branch information
xoen committed Oct 10, 2024
1 parent 11244ee commit 03215b5
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 20 deletions.
25 changes: 13 additions & 12 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ struct Args {

#[clap()]
/// numerical value for a region (1-17) or first part of a UK postcode
pub target: String,
pub target: Target,
}

#[tokio::main]
async fn main() {
let args = Args::parse();

// let target: Target = args.value.parse().unwrap_or(Target::NATIONAL);
let target: Target = args.target.parse().unwrap();
let target: Target = args.target;

// look for a range if a date was specified
if let Some(start_date) = &args.start_date {
Expand Down Expand Up @@ -64,8 +64,9 @@ fn handle_result(result: Result<i32, ApiError>, target: &Target) {
mod tests {
use clap::Parser;

use crate::Args;
// use clap::CommandFactory;
use carbonintensity::Region;

use crate::{Args, Target};

fn parsed_args(args: Vec<&str>) -> Result<Args, clap::Error> {
let args = ["carbonintensity-api"].iter().chain(args.iter());
Expand All @@ -75,22 +76,22 @@ mod tests {
#[test]
fn cli_valid_arguments() {
// single postcode
let args: Args = parsed_args(vec!["BS7"]).unwrap();
assert_eq!(args.target, "BS7");
let args: Args = parsed_args(vec!["bs7"]).unwrap();
assert_eq!(args.target, Target::Postcode("bs7".to_string()));

// single region id
parsed_args(vec!["13"]).unwrap();
assert_eq!(args.target, "BS7");
let args = parsed_args(vec!["13"]).unwrap();
assert_eq!(args.target, Target::Region(Region::London));

// start date / postcode
let args = parsed_args(vec!["--start-date", "2024-05-06", "BS7"]).unwrap();
assert_eq!(args.start_date, Some("2024-05-06".to_string()));
assert_eq!(args.target, "BS7".to_string());
assert_eq!(args.target, Target::Postcode("BS7".to_string()));

// start date / region id
let args = parsed_args(vec!["--start-date", "2024-05-06", "13"]).unwrap();
let args = parsed_args(vec!["--start-date", "2024-05-06", "16"]).unwrap();
assert_eq!(args.start_date, Some("2024-05-06".to_string()));
assert_eq!(args.target, "13".to_string());
assert_eq!(args.target, Target::Region(Region::Scotland));

// start date / end date
let args = parsed_args(vec![
Expand All @@ -103,7 +104,7 @@ mod tests {
.unwrap();
assert_eq!(args.start_date, Some("2024-05-06".to_string()));
assert_eq!(args.end_date, Some("2024-07-08".to_string()));
assert_eq!(args.target, "BS7".to_string());
assert_eq!(args.target, Target::Postcode("BS7".to_string()));

// short names
parsed_args(vec!["-s 2024-05-06", "-e 2024-05-06", "BS7"]).unwrap();
Expand Down
29 changes: 21 additions & 8 deletions src/target.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,40 @@
use std::str::FromStr;

use crate::Region;

/// Carbon intensity target, e.g. a postcode or a region
#[derive(Debug, Clone, PartialEq)]
pub enum Target {
// NATIONAL,
Postcode(String),
Region(Region),
}

impl FromStr for Target {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
/// Creates a `Target` from a `String`
///
/// If the string contains a valid `Region` id this returns a `Target::Region`,
/// otherwise it returns a `Target::Postcode`.
///
/// Note how this is infallible because it balls back to `Target::Postcode`.
///
/// ```
/// # use carbonintensity::{Target, Region};
/// let target = Target::from("13".to_string());
/// assert_eq!(target, Target::Region(Region::London));
///
/// let target = Target::from("BS7".to_string());
/// let bs7 = Target::Postcode("BS7".to_string());
/// assert_eq!(target, bs7);
/// ```
impl From<String> for Target {
fn from(s: String) -> Self {
//"" => Ok(Target::NATIONAL)

// Check if input can be parsed as a Region
if let Ok(region) = s.parse::<Region>() {
return Ok(Target::Region(region));
return Self::Region(region);
}

// Assumes the string was a postcode
Ok(Target::Postcode(s.to_string()))
Self::Postcode(s)
}
}

Expand Down

0 comments on commit 03215b5

Please sign in to comment.