Skip to main content

soma_cli_core/
output.rs

1//! Output-format selection.
2//!
3//! Most CLI subcommands support a human-readable default and a `--json`
4//! escape hatch for scripting. [`OutputFormat`] names that choice so
5//! commands can branch on it instead of threading a raw `bool` around.
6
7/// The two output shapes a CLI subcommand typically supports.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9pub enum OutputFormat {
10    #[default]
11    Human,
12    Json,
13}
14
15impl OutputFormat {
16    /// Map the conventional `--json` boolean flag to a format.
17    pub fn from_json_flag(json: bool) -> Self {
18        if json { Self::Json } else { Self::Human }
19    }
20
21    pub fn is_json(self) -> bool {
22        matches!(self, Self::Json)
23    }
24
25    pub fn is_human(self) -> bool {
26        matches!(self, Self::Human)
27    }
28}
29
30/// Render `human` or `json` depending on `format`, returning owned `String`s
31/// so callers can print, log, or compare either branch uniformly.
32pub fn render<H, J>(format: OutputFormat, human: H, json: J) -> String
33where
34    H: FnOnce() -> String,
35    J: FnOnce() -> String,
36{
37    match format {
38        OutputFormat::Human => human(),
39        OutputFormat::Json => json(),
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn from_json_flag_maps_correctly() {
49        assert_eq!(OutputFormat::from_json_flag(true), OutputFormat::Json);
50        assert_eq!(OutputFormat::from_json_flag(false), OutputFormat::Human);
51    }
52
53    #[test]
54    fn render_dispatches_to_matching_branch() {
55        let out = render(
56            OutputFormat::Json,
57            || "human".to_string(),
58            || "json".to_string(),
59        );
60        assert_eq!(out, "json");
61    }
62}