From 9d25987f583a75cb9dd8140b2028257001edc3f0 Mon Sep 17 00:00:00 2001 From: Brage <37003366+brage-andreas@users.noreply.github.com> Date: Fri, 22 Mar 2024 20:22:03 +0100 Subject: [PATCH] Refactor codebase and add helper functions (#6) This PR: - Updates various variable names - Updates file names - Adds helper functions - Adds user mentions to slash command replies --- .../{roulette.json => fortune_phrases.json} | 0 config/{pizza.json => pizzas.json} | 0 src/roulette.rs | 63 ++++++++----------- src/slack.rs | 12 ++-- 4 files changed, 31 insertions(+), 44 deletions(-) rename config/{roulette.json => fortune_phrases.json} (100%) rename config/{pizza.json => pizzas.json} (100%) diff --git a/config/roulette.json b/config/fortune_phrases.json similarity index 100% rename from config/roulette.json rename to config/fortune_phrases.json diff --git a/config/pizza.json b/config/pizzas.json similarity index 100% rename from config/pizza.json rename to config/pizzas.json diff --git a/src/roulette.rs b/src/roulette.rs index 4149680..2b34627 100644 --- a/src/roulette.rs +++ b/src/roulette.rs @@ -1,22 +1,15 @@ use lazy_static::lazy_static; -use rand::Rng; +use rand::seq::SliceRandom; use serde::{de::DeserializeOwned, Deserialize}; -enum JsonFile { - Pizza, - Roulette, -} - -pub enum SpinMode { +pub enum RouletteFilter { + All, Vegan, Vegetarian, - Any, } -trait Deserializable: DeserializeOwned {} - #[derive(Debug, Clone, Deserialize)] -pub struct PizzaDetail { +pub struct PizzaEntry { pub name: String, pub extra: String, pub description: String, @@ -25,44 +18,38 @@ pub struct PizzaDetail { } #[derive(Debug, Clone, Deserialize)] -pub struct RouletteMessage { - phrase: String, +pub struct FortunePhraseEntry { + pub phrase: String, } -impl Deserializable for PizzaDetail {} -impl Deserializable for RouletteMessage {} - lazy_static! { - static ref PIZZA_OPTIONS: Vec = load_from_json(JsonFile::Pizza); - static ref ROULETTE_MESSAGES: Vec = load_from_json(JsonFile::Roulette); + static ref PIZZAS: Vec = load_json(include_str!("../config/pizzas.json")); + static ref FORTUNE_PHRASES: Vec = + load_json(include_str!("../config/fortune_phrases.json")); } -fn load_from_json(file: JsonFile) -> Vec { - let json = match file { - JsonFile::Pizza => include_str!("../config/pizza.json"), - JsonFile::Roulette => include_str!("../config/roulette.json"), - }; - let result: Vec = serde_json::from_str(json).expect("Failed to parse JSON configuration"); - result +fn load_json(include_str: &str) -> Vec { + serde_json::from_str(include_str).expect("Failed to parse JSON configuration") } -pub fn get_random_pizza(mode: SpinMode) -> PizzaDetail { +fn get_random_element(source: &[T]) -> Option<&T> { let mut rng = rand::thread_rng(); - let mut filtered_pizzas: Vec<&PizzaDetail> = PIZZA_OPTIONS + source.choose(&mut rng) +} + +pub fn get_random_pizza(filter: RouletteFilter) -> &'static PizzaEntry { + let filtered_pizzas: Vec<&PizzaEntry> = PIZZAS .iter() - .filter(|p| match mode { - SpinMode::Vegan => p.vegan, - SpinMode::Vegetarian => p.vegetarian, - SpinMode::Any => true, + .filter(|pizza_entry| match filter { + RouletteFilter::All => true, + RouletteFilter::Vegan => pizza_entry.vegan, + RouletteFilter::Vegetarian => pizza_entry.vegetarian, }) .collect(); - let random_index = rng.gen_range(0..filtered_pizzas.len()); - filtered_pizzas.remove(random_index).clone() + + get_random_element(&filtered_pizzas).expect("PizzaEntry vector is empty") } -pub fn get_random_roulette_message() -> String { - let mut rng = rand::thread_rng(); - let phrases = ROULETTE_MESSAGES.to_vec(); - let random_index = rng.gen_range(0..phrases.len()); - phrases.get(random_index).unwrap().phrase.clone() +pub fn get_random_fortune_phrase() -> &'static FortunePhraseEntry { + get_random_element(&FORTUNE_PHRASES).expect("FortunePhrases vector is empty") } diff --git a/src/slack.rs b/src/slack.rs index f8aadb8..8cb34a0 100644 --- a/src/slack.rs +++ b/src/slack.rs @@ -1,4 +1,4 @@ -use crate::roulette::{get_random_pizza, get_random_roulette_message, SpinMode}; +use crate::roulette::{get_random_fortune_phrase, get_random_pizza, RouletteFilter}; use crate::slack_message::incoming; use crate::slack_message::outgoing; use reqwest::header::{HeaderMap, HeaderValue}; @@ -152,9 +152,9 @@ async fn handle_slash_command( message: incoming::Incoming, ) -> outgoing::SlackOutgoingMessage { let spin_mode = match message.payload.command.as_str() { - "/spin" => SpinMode::Any, - "/spin-vegan" => SpinMode::Vegan, - "/spin-vegetarian" => SpinMode::Vegetarian, + "/spin" => RouletteFilter::All, + "/spin-vegan" => RouletteFilter::Vegan, + "/spin-vegetarian" => RouletteFilter::Vegetarian, _ => { tracing::warn!("Received unknown command: {}", message.payload.command); return outgoing::SlackOutgoingMessage::Empty(outgoing::Outgoing::new( @@ -166,7 +166,7 @@ async fn handle_slash_command( let pizza = get_random_pizza(spin_mode); let mention = mention_user(message.payload.user_id); - let roulette_message = get_random_roulette_message(); + let fortune_phrase = get_random_fortune_phrase(); let outgoing_message = outgoing::SlashCommandOutgoingMessage { response_type: "in_channel".to_string(), @@ -175,7 +175,7 @@ async fn handle_slash_command( r#type: "section".to_string(), text: outgoing::SlackCommandBlockText { r#type: "mrkdwn".to_string(), - text: format!("{} {} *{}* 🎉", mention, roulette_message, pizza.name), + text: format!("{} {} *{}* 🎉", mention, fortune_phrase.phrase, pizza.name), }, }, outgoing::SlackCommandBlock {