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 {
19            Self::Json
20        } else {
21            Self::Human
22        }
23    }
24
25    pub fn is_json(self) -> bool {
26        matches!(self, Self::Json)
27    }
28
29    pub fn is_human(self) -> bool {
30        matches!(self, Self::Human)
31    }
32}
33
34/// Render `human` or `json` depending on `format`, returning owned `String`s
35/// so callers can print, log, or compare either branch uniformly.
36pub fn render<H, J>(format: OutputFormat, human: H, json: J) -> String
37where
38    H: FnOnce() -> String,
39    J: FnOnce() -> String,
40{
41    match format {
42        OutputFormat::Human => human(),
43        OutputFormat::Json => json(),
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn from_json_flag_maps_correctly() {
53        assert_eq!(OutputFormat::from_json_flag(true), OutputFormat::Json);
54        assert_eq!(OutputFormat::from_json_flag(false), OutputFormat::Human);
55    }
56
57    #[test]
58    fn render_dispatches_to_matching_branch() {
59        let out = render(
60            OutputFormat::Json,
61            || "human".to_string(),
62            || "json".to_string(),
63        );
64        assert_eq!(out, "json");
65    }
66}