diff --git a/README.md b/README.md index 2028924f..6d7a6388 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Supported languages * **R** ([*styler*](https://github.com/r-lib/styler)) * **Reason** ([*bsrefmt*](https://github.com/glennsl/bs-refmt)) * **ReScript** ([*rescript format*](https://www.npmjs.com/package/rescript)) -* **Ruby** ([*rufo*](https://github.com/ruby-formatter/rufo)) +* **Ruby** ([*rubocop*](https://github.com/rubocop/rubocop), [*rufo*](https://github.com/ruby-formatter/rufo), [*standardrb*](https://github.com/testdouble/standard)) * **Rust** ([*rustfmt*](https://github.com/rust-lang-nursery/rustfmt)) * **Scala** ([*scalafmt*](https://github.com/scalameta/scalafmt)) * **Shell script** ([*beautysh*](https://github.com/lovesegfault/beautysh), [*shfmt*](https://github.com/mvdan/sh)) diff --git a/format-all.el b/format-all.el index db783e72..7db9b7fd 100644 --- a/format-all.el +++ b/format-all.el @@ -66,8 +66,9 @@ ;; - Python (black, yapf) ;; - R (styler) ;; - Reason (bsrefmt) +;; - ReScript (resfmt) ;; - ReScript (rescript) -;; - Ruby (rufo) +;; - Ruby (rubocop, rufo, standardrb) ;; - Rust (rustfmt) ;; - Scala (scalafmt) ;; - Shell script (beautysh, shfmt) @@ -479,6 +480,40 @@ If ARGS are given, those are arguments to EXECUTABLE. They don't need to be shell-quoted." (apply 'format-all--buffer-hard nil nil nil executable args)) +(defun format-all--ruby-gem-bundled-p (gem-name) + "Internal helper function to check if GEM-NAME is listed in the current project's Gemfile.lock." + (let* ((lockfile "Gemfile.lock") + (dir (locate-dominating-file (buffer-file-name) lockfile))) + (and dir + (with-temp-buffer + (insert-file-contents (expand-file-name lockfile dir)) + (re-search-forward (format "^ %s " (regexp-quote gem-name)) nil t)) + t))) + +(defun format-all--buffer-hard-ruby + (gem-name ok-statuses error-regexp root-files executable &rest args) + "Internal helper function to implement ruby based formatters. + +GEM-NAME is the name of a Ruby gem required to run EXECUTABLE. + +For OK-STATUSES, ERROR-REGEXP, ROOT-FILES, EXECUTABLE and ARGS, see `format-all--buffer-hard'." + (let* ((error-regexp + (apply #'regexp-or + "Bundler::GemNotFound" + (concat "bundler: failed to load command: " + (regexp-quote executable)) + (concat (regexp-or "bundle" (regexp-quote executable)) + ": command not found") + (if error-regexp (list error-regexp)))) + (command-args + (append (if (format-all--ruby-gem-bundled-p gem-name) + '("bundle" "exec")) + (cons executable (format-all--flatten-once args))))) + (format-all--buffer-hard + ok-statuses error-regexp root-files + (car command-args) + (cdr command-args)))) + (defvar format-all--executable-table (make-hash-table) "Internal table of formatter executable names for format-all.") @@ -891,12 +926,26 @@ Consult the existing formatters for examples of BODY." (:install "gem install rufo") (:languages "Ruby") (:format - (format-all--buffer-easy - executable + (format-all--buffer-hard-ruby + "rufo" nil nil nil + "rufo" "--simple-exit" (when (buffer-file-name) (list "--filename" (buffer-file-name)))))) +(define-format-all-formatter rubocop + (:executable "rubocop") + (:install "gem install rubocop:'>=1.4.0'") + (:languages "Ruby") + (:format + (format-all--buffer-hard-ruby + "rubocop" '(0 1) nil nil + "rubocop" + "--auto-correct" + "--format" "quiet" + "--stderr" + "--stdin" (or (buffer-file-name) (buffer-name))))) + (define-format-all-formatter rustfmt (:executable "rustfmt") (:install "rustup component add rustfmt") @@ -964,6 +1013,17 @@ Consult the existing formatters for examples of BODY." '(0 1) ".*?:.*?:[0-9]+:[0-9]+: Parsing error:" nil executable "--fix" "--stdin"))) +(define-format-all-formatter standardrb + (:executable "standardrb") + (:install "gem install standard:'>=0.13.0'") + (:languages "Ruby") + (:format + (format-all--buffer-hard-ruby + "standard" '(0 1) nil nil + "standardrb" + "--fix" + "--stdin" (or (buffer-file-name) (buffer-name))))) + (define-format-all-formatter styler (:executable "Rscript") (:install "Rscript -e \"install.packages('styler')\"")