git-gamble 2.14.1

blend TDD + TCR to make sure to develop the right thing 😌, baby step by baby step πŸ‘ΆπŸ¦Ά
Documentation
use std::collections::HashMap;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;

use clap::ValueEnum;
use clap::builder::PossibleValue;

#[derive(Clone, Debug)]
pub enum Hook {
	Assistant,
	RealTimeCollaboration,
	Sound,
	TimeKeeper,
	TimeKeeperGitOnly,
}

impl ValueEnum for Hook {
	fn value_variants<'a>() -> &'a [Self] {
		&[
			Hook::Assistant,
			Hook::RealTimeCollaboration,
			Hook::Sound,
			Hook::TimeKeeper,
			Hook::TimeKeeperGitOnly,
		]
	}

	fn to_possible_value(&self) -> Option<PossibleValue> {
		// TODO find a way to factorise with hook_name : objective single source of truth
		Some(PossibleValue::new(match self {
			Hook::Assistant => "assistant",
			Hook::RealTimeCollaboration => "real-time-collaboration",
			Hook::Sound => "sound",
			Hook::TimeKeeper => "time-keeper",
			Hook::TimeKeeperGitOnly => "time-keeper-git-only",
		}))
	}
}

impl Display for Hook {
	fn fmt(&self, f: &mut Formatter<'_>) -> Result {
		write!(f, "{}", self.hook_name())
	}
}

impl Hook {
	pub(crate) fn hook_name(&self) -> &str {
		match self {
			Hook::Assistant => "assistant",
			Hook::RealTimeCollaboration => "real-time-collaboration",
			Hook::Sound => "sound",
			Hook::TimeKeeper => "time-keeper",
			Hook::TimeKeeperGitOnly => "time-keeper-git-only",
		}
	}

	pub(crate) fn hooks(&self) -> HashMap<&str, String> {
		match self {
			Hook::Assistant => HashMap::from([(
				"post-gamble",
				self.add_generated_watermark(include_str!(
					"../../../.config/git/hooks/post-gamble.assistant.sample.sh"
				)),
			)]),
			Hook::RealTimeCollaboration => HashMap::from([(
				"post-gamble",
				self.add_generated_watermark(include_str!(
					"../../../.config/git/hooks/post-gamble.real-time-collaboration.sample.sh"
				)),
			)]),
			Hook::Sound => HashMap::from([(
				"post-gamble",
				self.add_generated_watermark(include_str!(
					"../../../.config/git/hooks/post-gamble.sound.sample.sh"
				)),
			)]),
			Hook::TimeKeeper => HashMap::from([
				(
					"pre-gamble",
					self.add_generated_watermark(include_str!(
						"../../../.config/git/hooks/pre-gamble.time-keeper.sample.sh"
					)),
				),
				(
					"post-gamble",
					self.add_generated_watermark(include_str!(
						"../../../.config/git/hooks/post-gamble.time-keeper.sample.sh"
					)),
				),
			]),
			Hook::TimeKeeperGitOnly => HashMap::from([
				(
					"pre-commit",
					self.add_generated_watermark(include_str!(
						"../../../.config/git/hooks/pre-commit.time-keeper-git-only.sample.sh"
					)),
				),
				(
					"post-commit",
					self.add_generated_watermark(include_str!(
						"../../../.config/git/hooks/post-commit.time-keeper-git-only.sample.sh"
					)),
				),
			]),
		}
	}

	fn add_generated_watermark(&self, script: &str) -> String {
		let generated = [
			"",
			"#",
			"# This file have been generated by the following command :",
			format!("# git gamble hook enable {self}").as_str(),
			"#",
			"# This hook can be disabled by executing the following command :",
			format!("# git gamble hook disable {self}").as_str(),
		]
		.join("\n");

		let shebang_sh = "#!/usr/bin/env sh";
		let shebang_bash = "#!/usr/bin/env bash";

		script
			.replace(shebang_sh, &(shebang_sh.to_string() + &generated))
			.replace(shebang_bash, &(shebang_bash.to_string() + &generated))
	}
}