Repository: yshavit/mdq
Pull request #131 (2024-07-17 03:52:01)

move Cli to separate file
Just a straight move, no logic change at all.


Patch:
diff --git a/src/cli.rs b/src/cli.rs
new file mode 100644
index 0000000..0b37007
--- /dev/null
+++ b/src/cli.rs
@@ -0,0 +1,144 @@
+use crate::fmt_md::ReferencePlacement;
+use crate::link_transform::LinkTransform;
+use clap::{Parser, ValueEnum};
+use std::borrow::Cow;
+use std::fmt::{Display, Formatter};
+
+#[derive(Parser, Debug)]
+#[command(version, about, long_about = None)]
+pub struct Cli {
+    /// Where to put link references.
+    ///
+    /// For links and images of style `[description][1]`, this flag controls where to put the `[1]: https://example.com`
+    /// definition.
+    #[arg(long, value_enum, default_value_t=ReferencePlacement::Section)]
+    pub(crate) link_pos: ReferencePlacement,
+
+    /// Where to put footnote references. Defaults to be same as --link-pos
+    #[arg(long, value_enum)]
+    pub(crate) footnote_pos: Option<ReferencePlacement>,
+
+    #[arg(long, short, value_enum, default_value_t=LinkTransform::Reference)]
+    pub(crate) link_format: LinkTransform,
+
+    /// Output the results as a JSON object, instead of as markdown.
+    #[arg(long, short, default_value_t = OutputFormat::Markdown)]
+    pub(crate) output: OutputFormat,
+
+    #[arg(
+        short = ' ',
+        hide = true,
+        group = "selectors_group",
+        value_name = "selectors starting with list"
+    )]
+    pub(crate) list_selector: Option<String>,
+
+    /// The selectors string
+    #[arg(group = "selectors_group", value_name = "selectors")]
+    pub(crate) selectors: Option<String>,
+
+    /// Quiet: do not print anything to stdout. The exit code will still be 0 if-and-only-iff any elements match.
+    #[arg(long, short)]
+    pub(crate) quiet: bool,
+}
+
+impl Cli {
+    pub fn selector_string(&self) -> Cow<String> {
+        match &self.selectors {
+            Some(s) => Cow::Borrowed(s),
+            None => match &self.list_selector {
+                Some(list_selectors) => {
+                    let mut reconstructed = String::with_capacity(list_selectors.len() + 2);
+                    reconstructed.push_str("- ");
+                    reconstructed.push_str(list_selectors);
+                    Cow::Owned(reconstructed)
+                }
+                None => Cow::Owned(String::new()),
+            },
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
+pub enum OutputFormat {
+    /// Output results as Markdown.
+    Markdown,
+
+    /// Alias for markdown
+    Md,
+
+    /// Output results as JSON. Spans of inline elements (like within a single paragraph) will be rendered as a single string of
+    /// Markdown, not as separate JSON elements.
+    Json,
+}
+
+impl Display for OutputFormat {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        let self_str = match self {
+            OutputFormat::Markdown | OutputFormat::Md => "markdown",
+            OutputFormat::Json => "json",
+        };
+        f.write_str(self_str)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::cli::Cli;
+    use crate::unwrap;
+    use clap::{Error, Parser};
+
+    #[test]
+    fn verify_cli() {
+        use crate::cli::Cli;
+        use clap::CommandFactory;
+        Cli::command().debug_assert();
+    }
+
+    #[test]
+    fn standard_selectors() {
+        let result = Cli::try_parse_from(["mdq", "# hello"]);
+        unwrap!(result, Ok(cli));
+        assert_eq!(cli.selector_string().as_str(), "# hello");
+    }
+
+    #[test]
+    fn two_standard_selectors() {
+        let result = Cli::try_parse_from(["mdq", "# hello", "# world"]);
+        check_err(&result, "unexpected argument '# world' found");
+    }
+
+    #[test]
+    fn start_with_list_selectors() {
+        let result = Cli::try_parse_from(["mdq", "- world"]);
+        unwrap!(result, Ok(cli));
+        assert_eq!(cli.selector_string().as_str(), "- world");
+    }
+
+    #[test]
+    fn start_with_list_selectors_twice() {
+        let result = Cli::try_parse_from(["mdq", "- hello", "- world"]);
+        check_err(
+            &result,
+            "the argument '-  <selectors starting with list>' cannot be used multiple times",
+        );
+    }
+
+    #[test]
+    fn both_list_and_std_selectors() {
+        let result = Cli::try_parse_from(["mdq", "# hello", "- world"]);
+        check_err(
+            &result,
+            "the argument '[selectors]' cannot be used with '-  <selectors starting with list>'",
+        )
+    }
+
+    fn check_err(result: &Result<Cli, Error>, expect: &str) {
+        unwrap!(result, Err(e));
+        let e_str = e.to_string();
+        let first_line = e_str.split('\n').next().expect("no error string found");
+        let mut expect_full = "error: ".to_string();
+        expect_full.push_str(expect);
+        assert_eq!(first_line, &expect_full);
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 28249e4..425b17b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,13 +1,10 @@
-use clap::{Parser, ValueEnum};
+use cli::{Cli, OutputFormat};
 use output::Output;
-use std::borrow::Cow;
-use std::fmt::{Display, Formatter};
 use std::io;
 use std::io::{stdin, Read, Write};
 
-use crate::fmt_md::{MdOptions, ReferencePlacement};
+use crate::fmt_md::MdOptions;
 use crate::fmt_md_inlines::MdInlinesWriterOptions;
-use crate::link_transform::LinkTransform;
 use crate::output::Stream;
 use crate::select::ParseError;
 use crate::tree::{MdElem, ReadOptions};
@@ -15,6 +12,7 @@ use crate::tree_ref::MdElemRef;
 use crate::tree_ref_serde::SerdeDoc;
 use select::MdqRefSelector;
 
+pub mod cli;
 mod fmt_md;
 mod fmt_md_inlines;
 mod fmt_str;
@@ -31,84 +29,6 @@ mod tree_ref_serde;
 mod tree_test_utils;
 mod utils_for_test;
 
-#[derive(Parser, Debug)]
-#[command(version, about, long_about = None)]
-pub struct Cli {
-    /// Where to put link references.
-    ///
-    /// For links and images of style `[description][1]`, this flag controls where to put the `[1]: https://example.com`
-    /// definition.
-    #[arg(long, value_enum, default_value_t=ReferencePlacement::Section)]
-    pub(crate) link_pos: ReferencePlacement,
-
-    /// Where to put footnote references. Defaults to be same as --link-pos
-    #[arg(long, value_enum)]
-    pub(crate) footnote_pos: Option<ReferencePlacement>,
-
-    #[arg(long, short, value_enum, default_value_t=LinkTransform::Reference)]
-    pub(crate) link_format: LinkTransform,
-
-    /// Output the results as a JSON object, instead of as markdown.
-    #[arg(long, short, default_value_t = OutputFormat::Markdown)]
-    pub(crate) output: OutputFormat,
-
-    #[arg(
-        short = ' ',
-        hide = true,
-        group = "selectors_group",
-        value_name = "selectors starting with list"
-    )]
-    pub(crate) list_selector: Option<String>,
-
-    /// The selectors string
-    #[arg(group = "selectors_group", value_name = "selectors")]
-    pub(crate) selectors: Option<String>,
-
-    /// Quiet: do not print anything to stdout. The exit code will still be 0 if-and-only-iff any elements match.
-    #[arg(long, short)]
-    pub(crate) quiet: bool,
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
-pub enum OutputFormat {
-    /// Output results as Markdown.
-    Markdown,
-
-    /// Alias for markdown
-    Md,
-
-    /// Output results as JSON. Spans of inline elements (like within a single paragraph) will be rendered as a single string of
-    /// Markdown, not as separate JSON elements.
-    Json,
-}
-
-impl Display for OutputFormat {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        let self_str = match self {
-            OutputFormat::Markdown | OutputFormat::Md => "markdown",
-            OutputFormat::Json => "json",
-        };
-        f.write_str(self_str)
-    }
-}
-
-impl Cli {
-    fn selector_string(&self) -> Cow<String> {
-        match &self.selectors {
-            Some(s) => Cow::Borrowed(s),
-            None => match &self.list_selector {
-                Some(list_selectors) => {
-                    let mut reconstructed = String::with_capacity(list_selectors.len() + 2);
-                    reconstructed.push_str("- ");
-                    reconstructed.push_str(list_selectors);
-                    Cow::Owned(reconstructed)
-                }
-                None => Cow::Owned(String::new()),
-            },
-        }
-    }
-}
-
 pub fn run_in_memory(cli: &Cli, contents: &str) -> (bool, String) {
     let mut out = Vec::with_capacity(256); // just a guess
 
@@ -190,62 +110,3 @@ fn print_select_parse_error(original_string: &str, err: ParseError) {
         }
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use clap::Error;
-
-    #[test]
-    fn verify_cli() {
-        use clap::CommandFactory;
-        Cli::command().debug_assert();
-    }
-
-    #[test]
-    fn standard_selectors() {
-        let result = Cli::try_parse_from(["mdq", "# hello"]);
-        unwrap!(result, Ok(cli));
-        assert_eq!(cli.selector_string().as_str(), "# hello");
-    }
-
-    #[test]
-    fn two_standard_selectors() {
-        let result = Cli::try_parse_from(["mdq", "# hello", "# world"]);
-        check_err(&result, "unexpected argument '# world' found");
-    }
-
-    #[test]
-    fn start_with_list_selectors() {
-        let result = Cli::try_parse_from(["mdq", "- world"]);
-        unwrap!(result, Ok(cli));
-        assert_eq!(cli.selector_string().as_str(), "- world");
-    }
-
-    #[test]
-    fn start_with_list_selectors_twice() {
-        let result = Cli::try_parse_from(["mdq", "- hello", "- world"]);
-        check_err(
-            &result,
-            "the argument '-  <selectors starting with list>' cannot be used multiple times",
-        );
-    }
-
-    #[test]
-    fn both_list_and_std_selectors() {
-        let result = Cli::try_parse_from(["mdq", "# hello", "- world"]);
-        check_err(
-            &result,
-            "the argument '[selectors]' cannot be used with '-  <selectors starting with list>'",
-        )
-    }
-
-    fn check_err(result: &Result<Cli, Error>, expect: &str) {
-        unwrap!(result, Err(e));
-        let e_str = e.to_string();
-        let first_line = e_str.split('\n').next().expect("no error string found");
-        let mut expect_full = "error: ".to_string();
-        expect_full.push_str(expect);
-        assert_eq!(first_line, &expect_full);
-    }
-}
diff --git a/src/main.rs b/src/main.rs
index 9d73a07..67e9040 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,6 @@
 use clap::Parser;
-use mdq::{run_stdio, Cli};
+use mdq::cli::Cli;
+use mdq::run_stdio;
 use std::process::ExitCode;
 
 fn main() -> ExitCode {


Test patch:
diff --git a/tests/integ_test.rs b/tests/integ_test.rs
index 1335bbf..cc6a334 100644
--- a/tests/integ_test.rs
+++ b/tests/integ_test.rs
@@ -11,7 +11,7 @@ struct Case<const N: usize> {
 impl<const N: usize> Case<N> {
     fn check(&self) {
         let all_cli_args = ["cmd"].iter().chain(&self.cli_args);
-        let cli = mdq::Cli::try_parse_from(all_cli_args).unwrap();
+        let cli = mdq::cli::Cli::try_parse_from(all_cli_args).unwrap();
         let (actual_success, actual_out) = mdq::run_in_memory(&cli, self.md);
         assert_eq!(actual_out, self.expect_output);
         assert_eq!(actual_success, self.expect_success);