diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7b25e73c..6f25ca13 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -197,5 +197,8 @@ jobs: - name: ktlint run: curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.2.1/ktlint && chmod a+x ktlint && sudo mv ktlint /usr/local/bin/ + - name: rufo + run: gem install rufo + - name: run tests run: cargo test diff --git a/README.md b/README.md index 2a7e3461..b88f345b 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ mdsf init | Python | `autopep8`, `black`, `blue`, `isort`, `ruff`, `usort`, `yapf` | | ReScript | `rescript_format` | | Roc | `roc_format` | -| Ruby | `rubocop` | +| Ruby | `rubocop`, `rufo` | | Rust | `rustfmt` | | Scala | `scalafmt` | | Shell | `beautysh`, `shfmt` | diff --git a/schemas/v0.0.2/mdsf.schema.json b/schemas/v0.0.2/mdsf.schema.json index 6488f2e7..c996dcc9 100644 --- a/schemas/v0.0.2/mdsf.schema.json +++ b/schemas/v0.0.2/mdsf.schema.json @@ -182,7 +182,7 @@ "java": { "default": { "enabled": true, - "formatter": ["google-java-format", "clang-format"] + "formatter": [["google-java-format", "clang-format"]] }, "allOf": [ { @@ -361,7 +361,7 @@ "ruby": { "default": { "enabled": true, - "formatter": "rubocop" + "formatter": [["rubocop", "rufo"]] }, "allOf": [ { @@ -1686,7 +1686,7 @@ }, "Ruby": { "type": "string", - "enum": ["rubocop"] + "enum": ["rubocop", "rufo"] }, "Rust": { "type": "string", diff --git a/src/formatters/mod.rs b/src/formatters/mod.rs index aa24b86e..94fd55c4 100644 --- a/src/formatters/mod.rs +++ b/src/formatters/mod.rs @@ -38,6 +38,7 @@ pub mod rescript_format; pub mod roc_format; pub mod rubocop; pub mod ruff; +pub mod rufo; pub mod rustfmt; pub mod scalafmt; pub mod shfmt; @@ -52,16 +53,18 @@ pub mod zigfmt; #[inline] pub fn setup_snippet(code: &str, file_ext: &str) -> std::io::Result { - let mut b = tempfile::Builder::new(); - - b.rand_bytes(12).suffix(file_ext); - - // ktlint wants PascalCase file names - if file_ext == Language::Kotlin.to_file_ext() { - b.prefix("MdsfFile"); - } - - let mut f = b.tempfile()?; + let mut f = tempfile::Builder::new() + .rand_bytes(12) + .suffix(file_ext) + .prefix( + // ktlint wants PascalCase file names + if file_ext == Language::Kotlin.to_file_ext() { + "MdsfFile" + } else { + "mdsf" + }, + ) + .tempfile()?; f.write_all(code.as_bytes())?; f.flush()?; diff --git a/src/formatters/rufo.rs b/src/formatters/rufo.rs new file mode 100644 index 00000000..5679e101 --- /dev/null +++ b/src/formatters/rufo.rs @@ -0,0 +1,43 @@ +use super::execute_command; + +#[inline] +pub fn format_using_rufo( + snippet_path: &std::path::Path, +) -> std::io::Result<(bool, Option)> { + let mut cmd = std::process::Command::new("rufo"); + + cmd.arg("--simple-exit").arg(snippet_path); + + execute_command(&mut cmd, snippet_path) +} + +#[cfg(test)] +mod test_rufo { + use crate::{ + formatters::{rufo::format_using_rufo, setup_snippet}, + languages::Language, + }; + + #[test_with::executable(rufo)] + #[test] + fn it_should_format_ruby() { + let input = "def add( a , b ) + return a + b + end"; + + let expected_output = "def add(a, b) + return a + b +end +"; + + let snippet = setup_snippet(input, Language::Ruby.to_file_ext()) + .expect("it to create a snippet file"); + + let output = format_using_rufo(snippet.path()) + .expect("it to be successful") + .1 + .expect("it to be some"); + + assert_eq!(expected_output, output); + } +} diff --git a/src/languages/java.rs b/src/languages/java.rs index 84f1f7e4..ddbb23ae 100644 --- a/src/languages/java.rs +++ b/src/languages/java.rs @@ -30,10 +30,10 @@ impl Default for Lang { impl Default for MdsfFormatter { #[inline] fn default() -> Self { - Self::Multiple(vec![ + Self::Multiple(vec![Self::Multiple(vec![ Self::Single(Java::GoogleJavaFormat), Self::Single(Java::ClangFormat), - ]) + ])]) } } diff --git a/src/languages/ruby.rs b/src/languages/ruby.rs index d4b0a87a..b8b22d53 100644 --- a/src/languages/ruby.rs +++ b/src/languages/ruby.rs @@ -1,6 +1,6 @@ use schemars::JsonSchema; -use crate::formatters::{rubocop::format_using_rubocop, MdsfFormatter}; +use crate::formatters::{rubocop::format_using_rubocop, rufo::format_using_rufo, MdsfFormatter}; use super::{Lang, LanguageFormatter}; @@ -10,6 +10,8 @@ pub enum Ruby { #[default] #[serde(rename = "rubocop")] RuboCop, + #[serde(rename = "rufo")] + Rufo, } impl Default for Lang { @@ -25,7 +27,10 @@ impl Default for Lang { impl Default for MdsfFormatter { #[inline] fn default() -> Self { - Self::Single(Ruby::RuboCop) + Self::Multiple(vec![Self::Multiple(vec![ + Self::Single(Ruby::RuboCop), + Self::Single(Ruby::Rufo), + ])]) } } @@ -37,6 +42,7 @@ impl LanguageFormatter for Ruby { ) -> std::io::Result<(bool, Option)> { match self { Self::RuboCop => format_using_rubocop(snippet_path), + Self::Rufo => format_using_rufo(snippet_path), } } } @@ -99,4 +105,28 @@ end assert_eq!(output, expected_output); } + + #[test_with::executable(rufo)] + #[test] + fn test_rufo() { + let expected_output = "def add(a, b) + return a + b +end +"; + + let l = Lang:: { + enabled: true, + formatter: MdsfFormatter::Single(Ruby::Rufo), + }; + + let snippet = setup_snippet(INPUT, EXTENSION).expect("it to save the file"); + let snippet_path = snippet.path(); + + let output = l + .format(snippet_path) + .expect("it to not fail") + .expect("it to be a snippet"); + + assert_eq!(output, expected_output); + } }