bar-rubble 0.5.2

Quickly generate output for viewing in swaybar or similar
Documentation
use crate::RubbleResult;
use clap::Args;
use reqwest;
use serde_json::{json, Value};
#[derive(Args)]
/// Wraps arguments for weather calls
pub struct WeatherArgs {
    /// Pass in a city to check weather using wttr.in
    #[arg(default_value = "portsmouth", short, long)]
    pub city: String,
}

impl WeatherArgs {
    pub fn empty() -> Self {
        Self {
            city: String::from(""),
        }
    }
}

#[derive(Debug)]
struct WeatherCondition {
    feelslike_c: String,
    temp_c: String,
    temp_f: String,
    humidity: String,
    icon: String,
    weather_desc: String,
}

impl WeatherCondition {
    fn to_json(&self) -> Value {
        json!({
          "feelslike_c": self.feelslike_c,
          "temp_c": self.temp_c,
          "temp_f": self.temp_f,
          "humidity": self.humidity,
          "icon": self.icon,
          "weather_desc": self.weather_desc
        })
    }
    fn new(
        feelslike_c: String,
        temp_c: String,
        temp_f: String,
        humidity: String,
        weather_desc: String,
    ) -> Self {
        Self {
            feelslike_c,
            temp_c,
            temp_f,
            humidity,
            icon: WeatherCondition::weather_icon(weather_desc.as_str()),
            weather_desc,
        }
    }

    fn weather_icon(weather_desc: &str) -> String {
        // https://github.com/chubin/wttr.in/blob/e0cc061a64ba86cda1380f0409203a0fb8ae889c/lib/constants.py
        let icon = match weather_desc {
            "Unknown" => "",
            "Cloudy" => "☁️",
            "Fog" => "🌫",
            "Heavy rain" => "🌧",
            "Heavy showers" => "🌧",
            "Heavy snow" => "❄️",
            "Heavy snow showers" => "❄️",
            "Light rain" => "🌦",
            "Light showers" => "🌦",
            "Light sleet" => "🌧",
            "Light sleet showers" => "🌧",
            "Light snow" => "🌨",
            "Light snow showers" => "🌨",
            "Partly cloudy" => "⛅️",
            "Sunny" => "☀️",
            "Thundery heavy rain" => "🌩",
            "Thundery showers" => "",
            "Thundery snow showers" => "",
            "Very cloudy" => "☁️",
            _ => "",
        };
        icon.to_string()
    }
}

async fn check_wttr(city: &String) -> Value {
    let url = format!("https://wttr.in/{}?format=j1", city);
    let body = reqwest::get(url).await.unwrap().text().await.unwrap();
    let wttr_json: Value = serde_json::from_str(body.as_str()).unwrap();
    wttr_json["current_condition"][0].clone()
}

pub async fn weather_json(args: &WeatherArgs) -> RubbleResult {
    let current_condition = check_wttr(&args.city).await;
    let weather = WeatherCondition::new(
        current_condition["FeelsLikeC"]
            .as_str()
            .unwrap()
            .to_string(),
        current_condition["temp_C"].as_str().unwrap().to_string(),
        current_condition["temp_F"].as_str().unwrap().to_string(),
        current_condition["humidity"].as_str().unwrap().to_string(),
        current_condition["weatherDesc"][0]["value"]
            .as_str()
            .unwrap()
            .to_string(),
    );

    let r = Ok(weather.to_json());
    RubbleResult::new(r, default_format())
}

crate::avaliable_formattings!(
    "{{feelslike_c}} {{icon}}",
    "feelslike_c temp_c temp_f humidity icon weather_desc"
);

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

    #[tokio::test]
    async fn test_weather_icon() {
        assert_eq!(WeatherCondition::weather_icon("Unknown"), "");
        assert_eq!(WeatherCondition::weather_icon("Cloudy"), "☁️");
        assert_eq!(WeatherCondition::weather_icon("Fog"), "🌫");
        assert_eq!(WeatherCondition::weather_icon("Heavy rain"), "🌧");
        assert_eq!(WeatherCondition::weather_icon("Heavy showers"), "🌧");
        assert_eq!(WeatherCondition::weather_icon("Heavy snow"), "❄️");
        assert_eq!(WeatherCondition::weather_icon("Heavy snow showers"), "❄️");
        assert_eq!(WeatherCondition::weather_icon("Light rain"), "🌦");
        assert_eq!(WeatherCondition::weather_icon("Light showers"), "🌦");
        assert_eq!(WeatherCondition::weather_icon("Light sleet"), "🌧");
        assert_eq!(WeatherCondition::weather_icon("Light sleet showers"), "🌧");
        assert_eq!(WeatherCondition::weather_icon("Light snow"), "🌨");
        assert_eq!(WeatherCondition::weather_icon("Light snow showers"), "🌨");
        assert_eq!(WeatherCondition::weather_icon("Partly cloudy"), "⛅️");
        assert_eq!(WeatherCondition::weather_icon("Sunny"), "☀️");
        assert_eq!(WeatherCondition::weather_icon("Thundery heavy rain"), "🌩");
        assert_eq!(WeatherCondition::weather_icon("Thundery showers"), "");
    }
}