From 773c11a4a6a144bdece481b8d98a59bc1d727ba8 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 27 Jan 2022 00:02:48 +0900 Subject: [PATCH 01/22] Add API used as -X or -T program --- src/pogonos/api.clj | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/pogonos/api.clj diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj new file mode 100644 index 0000000..039b14c --- /dev/null +++ b/src/pogonos/api.clj @@ -0,0 +1,16 @@ +(ns pogonos.api + (:require [pogonos.core :as pg] + [pogonos.output :as out] + [pogonos.reader :as reader])) + +(defn render [{:keys [string file resource data output] :as opts}] + (let [out (if output + (out/to-file output) + (out/to-stdout)) + opts' (-> opts + (assoc :output out) + (dissoc :string :file :resource :data))] + (cond string (pg/render-string string data opts') + file (pg/render-file file data opts') + resource (pg/render-resource resource data opts') + :else (pg/render-input (reader/->reader *in*) data opts')))) From 2f294f538ea3235c5ff1fe07800b56f3a35ab4fa Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 27 Jan 2022 00:32:46 +0900 Subject: [PATCH 02/22] Add :tools/usage so that lib can be used as CLI tool --- deps.edn | 1 + 1 file changed, 1 insertion(+) diff --git a/deps.edn b/deps.edn index 65c677b..909e928 100644 --- a/deps.edn +++ b/deps.edn @@ -1,5 +1,6 @@ {:paths ["src"] :deps {org.clojure/clojure {:mvn/version "1.10.3"}} + :tools/usage {:ns-default pogonos.api} :aliases {:check {:extra-deps {athos/clj-check {:git/url "https://github.com/athos/clj-check.git" From 64efbf59fa146f732fd30c621c5cb10740ae6493 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 27 Jan 2022 20:48:20 +0900 Subject: [PATCH 03/22] Coerce file paths to string to accept symbol paths --- src/pogonos/api.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 039b14c..592a684 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -5,12 +5,12 @@ (defn render [{:keys [string file resource data output] :as opts}] (let [out (if output - (out/to-file output) + (out/to-file (str output)) (out/to-stdout)) opts' (-> opts (assoc :output out) (dissoc :string :file :resource :data))] (cond string (pg/render-string string data opts') - file (pg/render-file file data opts') - resource (pg/render-resource resource data opts') + file (pg/render-file (str file) data opts') + resource (pg/render-resource (str resource) data opts') :else (pg/render-input (reader/->reader *in*) data opts')))) From ab4980dd454f3f7aca2f46b46e5d4df3a511ef6c Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 27 Jan 2022 20:50:24 +0900 Subject: [PATCH 04/22] Add :data-file option --- src/pogonos/api.clj | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 592a684..041a2c2 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -1,15 +1,23 @@ (ns pogonos.api - (:require [pogonos.core :as pg] + (:require [clojure.edn :as edn] + [clojure.java.io :as io] + [pogonos.core :as pg] [pogonos.output :as out] - [pogonos.reader :as reader])) + [pogonos.reader :as reader]) + (:import [java.io PushbackReader])) -(defn render [{:keys [string file resource data output] :as opts}] - (let [out (if output +(defn render [{:keys [string file resource data data-file output] :as opts}] + (let [data (or (when data-file + (with-open [r (-> (io/reader (str data-file)) + PushbackReader.)] + (edn/read r))) + data) + out (if output (out/to-file (str output)) (out/to-stdout)) opts' (-> opts (assoc :output out) - (dissoc :string :file :resource :data))] + (dissoc :string :file :resource :data :data-file))] (cond string (pg/render-string string data opts') file (pg/render-file (str file) data opts') resource (pg/render-resource (str resource) data opts') From 285eac2049564483f67f2009c96b3aaca8519fe6 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 27 Jan 2022 23:56:18 +0900 Subject: [PATCH 05/22] Add another API fn: check --- src/pogonos/api.clj | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 041a2c2..4474498 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -3,7 +3,8 @@ [clojure.java.io :as io] [pogonos.core :as pg] [pogonos.output :as out] - [pogonos.reader :as reader]) + [pogonos.reader :as reader] + [pogonos.error :as error]) (:import [java.io PushbackReader])) (defn render [{:keys [string file resource data data-file output] :as opts}] @@ -22,3 +23,15 @@ file (pg/render-file (str file) data opts') resource (pg/render-resource (str resource) data opts') :else (pg/render-input (reader/->reader *in*) data opts')))) + +(defn check [{:keys [string file resource] :as opts}] + (try + (cond string (pg/check-string string opts) + file (pg/check-file (str file) opts) + resource (pg/check-resource (str resource) opts) + :else (pg/check-input (reader/->reader *in*) opts)) + (catch Exception e + (if (::error/type (ex-data e)) + (throw (ex-info (str "Template parsing failed: " (ex-message e)) + (ex-data e))) + (throw e))))) From c4b17cad0179ce9654d2ae706d6b4492398ab619 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Mon, 14 Feb 2022 23:34:06 +0900 Subject: [PATCH 06/22] Support bulk check for specified dir(s) --- src/pogonos/api.clj | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 4474498..8c12578 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -1,11 +1,13 @@ (ns pogonos.api (:require [clojure.edn :as edn] [clojure.java.io :as io] + [clojure.string :as str] [pogonos.core :as pg] + [pogonos.error :as error] [pogonos.output :as out] - [pogonos.reader :as reader] - [pogonos.error :as error]) - (:import [java.io PushbackReader])) + [pogonos.reader :as reader]) + (:import [java.io File PushbackReader] + [java.util.regex Pattern])) (defn render [{:keys [string file resource data data-file output] :as opts}] (let [data (or (when data-file @@ -24,10 +26,21 @@ resource (pg/render-resource (str resource) data opts') :else (pg/render-input (reader/->reader *in*) data opts')))) -(defn check [{:keys [string file resource] :as opts}] +(def ^:private ^:const path-separator + (re-pattern (Pattern/quote (System/getProperty "path.separator")))) + +(defn- check-files [dir opts] + (let [dirs (str/split dir path-separator)] + (doseq [dir dirs + ^File file (file-seq (io/file dir)) + :when (.isFile file)] + (pg/check-file file opts)))) + +(defn check [{:keys [string file dir resource] :as opts}] (try (cond string (pg/check-string string opts) file (pg/check-file (str file) opts) + dir (check-files (str dir) opts) resource (pg/check-resource (str resource) opts) :else (pg/check-input (reader/->reader *in*) opts)) (catch Exception e From 205bc85ab054c4db9cd29680a0314fabcc1f3231 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Tue, 15 Feb 2022 23:57:25 +0900 Subject: [PATCH 07/22] Filter files to be checked with regex --- src/pogonos/api.clj | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 8c12578..fae0775 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -29,11 +29,20 @@ (def ^:private ^:const path-separator (re-pattern (Pattern/quote (System/getProperty "path.separator")))) -(defn- check-files [dir opts] - (let [dirs (str/split dir path-separator)] +(defn- str->matcher [s] + (comp boolean (partial re-find (re-pattern s)))) + +(defn- check-files [dirs {:keys [file-regex file-exclude-regex] :as opts}] + (let [include? (if file-regex + (str->matcher file-regex) + (constantly true)) + exclude? (if file-exclude-regex + (str->matcher file-exclude-regex) + (constantly false))] (doseq [dir dirs ^File file (file-seq (io/file dir)) - :when (.isFile file)] + :let [path (.getPath file)] + :when (and (.isFile file) (include? path) (not (exclude? path)))] (pg/check-file file opts)))) (defn check [{:keys [string file dir resource] :as opts}] From 369bce0ca22c003ad4d4396d551e5f1c794a12e8 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Wed, 16 Feb 2022 19:59:00 +0900 Subject: [PATCH 08/22] Accept sequential as dir --- src/pogonos/api.clj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index fae0775..6b5925b 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -49,7 +49,10 @@ (try (cond string (pg/check-string string opts) file (pg/check-file (str file) opts) - dir (check-files (str dir) opts) + dir (check-files (if (sequential? dir) + (mapv str dir) + (str/split (str dir) path-separator)) + opts) resource (pg/check-resource (str resource) opts) :else (pg/check-input (reader/->reader *in*) opts)) (catch Exception e From ebc43eced7c864f8df7b9cb52f1e6042f471ab02 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 17 Feb 2022 14:06:11 +0900 Subject: [PATCH 09/22] Check multiple files if specified --- src/pogonos/api.clj | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 6b5925b..c559a38 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -32,27 +32,38 @@ (defn- str->matcher [s] (comp boolean (partial re-find (re-pattern s)))) -(defn- check-files [dirs {:keys [file-regex file-exclude-regex] :as opts}] - (let [include? (if file-regex - (str->matcher file-regex) - (constantly true)) - exclude? (if file-exclude-regex - (str->matcher file-exclude-regex) - (constantly false))] - (doseq [dir dirs +(defn- check-inputs [inputs include? exclude? opts] + (let [include? (or include? (constantly true)) + exclude? (or exclude? (constantly false))] + (doseq [input inputs + :when (and (include? input) (not (exclude? input)))] + (with-open [r (reader/->reader input)] + (pg/check-input r opts))))) + +(defn- check-files [files {:keys [file-regex file-exclude-regex] :as opts}] + (let [include? (when file-regex + (comp (str->matcher file-regex) #(.getPath ^File %))) + exclude? (when file-exclude-regex + (comp (str->matcher file-exclude-regex) #(.getPath ^File %)))] + (check-inputs (map io/file files) include? exclude? opts))) + +(defn- check-dirs [dirs opts] + (-> (for [dir dirs ^File file (file-seq (io/file dir)) - :let [path (.getPath file)] - :when (and (.isFile file) (include? path) (not (exclude? path)))] - (pg/check-file file opts)))) + :when (.isFile file)] + file) + (check-files opts))) + +(defn- split-path [path] + (if (sequential? path) + (mapv str path) + (str/split (str path) path-separator))) (defn check [{:keys [string file dir resource] :as opts}] (try (cond string (pg/check-string string opts) - file (pg/check-file (str file) opts) - dir (check-files (if (sequential? dir) - (mapv str dir) - (str/split (str dir) path-separator)) - opts) + file (check-files (split-path file) opts) + dir (check-dirs (split-path dir) opts) resource (pg/check-resource (str resource) opts) :else (pg/check-input (reader/->reader *in*) opts)) (catch Exception e From 6cc25464afbc227498603ed9d9d5769b90840645 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 17 Feb 2022 14:07:19 +0900 Subject: [PATCH 10/22] Name template being checked during bulk check --- src/pogonos/api.clj | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index c559a38..f3535c3 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -35,8 +35,11 @@ (defn- check-inputs [inputs include? exclude? opts] (let [include? (or include? (constantly true)) exclude? (or exclude? (constantly false))] - (doseq [input inputs + (doseq [{:keys [name input]} inputs :when (and (include? input) (not (exclude? input)))] + (when-not (:quiet opts) + (binding [*out* *err*] + (println "Checking template" name))) (with-open [r (reader/->reader input)] (pg/check-input r opts))))) @@ -45,7 +48,10 @@ (comp (str->matcher file-regex) #(.getPath ^File %))) exclude? (when file-exclude-regex (comp (str->matcher file-exclude-regex) #(.getPath ^File %)))] - (check-inputs (map io/file files) include? exclude? opts))) + (-> (for [file files + :let [file (io/file file)]] + {:name (.getPath file) :input file}) + (check-inputs include? exclude? opts)))) (defn- check-dirs [dirs opts] (-> (for [dir dirs From d9346f6560c77cc098cc92662a5b8311ca8b6d46 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 17 Feb 2022 20:31:11 +0900 Subject: [PATCH 11/22] Check multiple resources if specified --- src/pogonos/api.clj | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index f3535c3..4167e86 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -32,26 +32,31 @@ (defn- str->matcher [s] (comp boolean (partial re-find (re-pattern s)))) -(defn- check-inputs [inputs include? exclude? opts] - (let [include? (or include? (constantly true)) - exclude? (or exclude? (constantly false))] +(defn- check-inputs [inputs {:keys [include-regex exclude-regex] :as opts}] + (let [include? (if include-regex + (str->matcher include-regex) + (constantly true)) + exclude? (if exclude-regex + (str->matcher exclude-regex) + (constantly false))] (doseq [{:keys [name input]} inputs - :when (and (include? input) (not (exclude? input)))] + :when (and (include? name) (not (exclude? name)))] (when-not (:quiet opts) (binding [*out* *err*] (println "Checking template" name))) (with-open [r (reader/->reader input)] (pg/check-input r opts))))) -(defn- check-files [files {:keys [file-regex file-exclude-regex] :as opts}] - (let [include? (when file-regex - (comp (str->matcher file-regex) #(.getPath ^File %))) - exclude? (when file-exclude-regex - (comp (str->matcher file-exclude-regex) #(.getPath ^File %)))] - (-> (for [file files - :let [file (io/file file)]] - {:name (.getPath file) :input file}) - (check-inputs include? exclude? opts)))) +(defn- check-files [files opts] + (-> (for [file files + :let [file (io/file file)]] + {:name (.getPath file) :input file}) + (check-inputs opts))) + +(defn- check-resources [resources opts] + (-> (for [res resources] + {:name res :input (io/resource res)}) + (check-inputs opts))) (defn- check-dirs [dirs opts] (-> (for [dir dirs @@ -69,8 +74,8 @@ (try (cond string (pg/check-string string opts) file (check-files (split-path file) opts) + resource (check-resources (split-path resource) opts) dir (check-dirs (split-path dir) opts) - resource (pg/check-resource (str resource) opts) :else (pg/check-input (reader/->reader *in*) opts)) (catch Exception e (if (::error/type (ex-data e)) From 566ab64ffe5209c8e923512202cf1c4c16d50a8e Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 17 Feb 2022 20:31:41 +0900 Subject: [PATCH 12/22] Allow to pass regexes as symbol --- src/pogonos/api.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 4167e86..2027c7d 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -30,7 +30,7 @@ (re-pattern (Pattern/quote (System/getProperty "path.separator")))) (defn- str->matcher [s] - (comp boolean (partial re-find (re-pattern s)))) + (comp boolean (partial re-find (re-pattern (str s))))) (defn- check-inputs [inputs {:keys [include-regex exclude-regex] :as opts}] (let [include? (if include-regex From 02825e92ba8921f49910853741cdb2043a68e3d0 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 17 Feb 2022 20:32:28 +0900 Subject: [PATCH 13/22] Include template name in check error messages --- src/pogonos/api.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 2027c7d..d19ff79 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -45,7 +45,7 @@ (binding [*out* *err*] (println "Checking template" name))) (with-open [r (reader/->reader input)] - (pg/check-input r opts))))) + (pg/check-input r (assoc opts :source name)))))) (defn- check-files [files opts] (-> (for [file files From 9e089211e3a3f2604810c4e7b38c5c78a7a9dd55 Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Thu, 17 Feb 2022 23:46:18 +0900 Subject: [PATCH 14/22] Accept coll of regexes as :include-/exclude-regex --- src/pogonos/api.clj | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index d19ff79..4f25ff6 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -29,15 +29,19 @@ (def ^:private ^:const path-separator (re-pattern (Pattern/quote (System/getProperty "path.separator")))) -(defn- str->matcher [s] - (comp boolean (partial re-find (re-pattern (str s))))) +(defn- ->matcher [x] + (let [regexes (if (coll? x) + (mapv (comp re-pattern str) x) + [(re-pattern (str x))])] + (fn [s] + (boolean (some #(re-find % s) regexes))))) (defn- check-inputs [inputs {:keys [include-regex exclude-regex] :as opts}] (let [include? (if include-regex - (str->matcher include-regex) + (->matcher include-regex) (constantly true)) exclude? (if exclude-regex - (str->matcher exclude-regex) + (->matcher exclude-regex) (constantly false))] (doseq [{:keys [name input]} inputs :when (and (include? name) (not (exclude? name)))] From 988d539c01a4ce487b20625805e95da2046271dc Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Fri, 18 Feb 2022 00:24:16 +0900 Subject: [PATCH 15/22] Report all syntax errors instead of only first one --- src/pogonos/api.clj | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 4f25ff6..073d318 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -36,6 +36,22 @@ (fn [s] (boolean (some #(re-find % s) regexes))))) +(def ^:private ^:dynamic *errors*) + +(defn- with-error-handling + ([f] (with-error-handling nil f)) + ([source f] + (try + (f) + (catch Exception e + (if (::error/type (ex-data e)) + (do (binding [*out* *err* + error/*source* source] + (print "[ERROR] ") + (pg/perr e)) + (set! *errors* (conj *errors* e))) + (throw e)))))) + (defn- check-inputs [inputs {:keys [include-regex exclude-regex] :as opts}] (let [include? (if include-regex (->matcher include-regex) @@ -49,7 +65,8 @@ (binding [*out* *err*] (println "Checking template" name))) (with-open [r (reader/->reader input)] - (pg/check-input r (assoc opts :source name)))))) + (with-error-handling name + #(pg/check-input r opts)))))) (defn- check-files [files opts] (-> (for [file files @@ -75,14 +92,12 @@ (str/split (str path) path-separator))) (defn check [{:keys [string file dir resource] :as opts}] - (try - (cond string (pg/check-string string opts) + (binding [*errors* []] + (cond string (with-error-handling #(pg/check-string string opts)) file (check-files (split-path file) opts) resource (check-resources (split-path resource) opts) dir (check-dirs (split-path dir) opts) - :else (pg/check-input (reader/->reader *in*) opts)) - (catch Exception e - (if (::error/type (ex-data e)) - (throw (ex-info (str "Template parsing failed: " (ex-message e)) - (ex-data e))) - (throw e))))) + :else (with-error-handling + #(pg/check-input (reader/->reader *in*) opts))) + (when (seq *errors*) + (System/exit 1)))) From 3017fce8d9fb4a2ee0e6fd540497b0fca31a536b Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Fri, 18 Feb 2022 15:08:28 +0900 Subject: [PATCH 16/22] Make action on failure configurable --- src/pogonos/api.clj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 073d318..7b1a4c4 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -91,7 +91,8 @@ (mapv str path) (str/split (str path) path-separator))) -(defn check [{:keys [string file dir resource] :as opts}] +(defn check + [{:keys [string file dir resource on-failure] :or {on-failure :exit} :as opts}] (binding [*errors* []] (cond string (with-error-handling #(pg/check-string string opts)) file (check-files (split-path file) opts) @@ -100,4 +101,7 @@ :else (with-error-handling #(pg/check-input (reader/->reader *in*) opts))) (when (seq *errors*) - (System/exit 1)))) + (case on-failure + :exit (System/exit 1) + :throw (throw (ex-info "Template checking failed" {:errors *errors*})) + nil)))) From 3ad584cdea0d6375c831feba9b791ec4899fbaca Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Fri, 18 Feb 2022 15:11:08 +0900 Subject: [PATCH 17/22] Make :quiet option hide error messages --- src/pogonos/api.clj | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 7b1a4c4..f613e09 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -39,16 +39,17 @@ (def ^:private ^:dynamic *errors*) (defn- with-error-handling - ([f] (with-error-handling nil f)) - ([source f] + ([opts f] (with-error-handling nil opts f)) + ([source opts f] (try (f) (catch Exception e (if (::error/type (ex-data e)) - (do (binding [*out* *err* - error/*source* source] - (print "[ERROR] ") - (pg/perr e)) + (do (when-not (:quiet opts) + (binding [*out* *err* + error/*source* source] + (print "[ERROR] ") + (pg/perr e))) (set! *errors* (conj *errors* e))) (throw e)))))) @@ -65,7 +66,7 @@ (binding [*out* *err*] (println "Checking template" name))) (with-open [r (reader/->reader input)] - (with-error-handling name + (with-error-handling name opts #(pg/check-input r opts)))))) (defn- check-files [files opts] @@ -94,11 +95,11 @@ (defn check [{:keys [string file dir resource on-failure] :or {on-failure :exit} :as opts}] (binding [*errors* []] - (cond string (with-error-handling #(pg/check-string string opts)) + (cond string (with-error-handling opts #(pg/check-string string opts)) file (check-files (split-path file) opts) resource (check-resources (split-path resource) opts) dir (check-dirs (split-path dir) opts) - :else (with-error-handling + :else (with-error-handling opts #(pg/check-input (reader/->reader *in*) opts))) (when (seq *errors*) (case on-failure From 3d793418109a646560f4304b2c7ca622f05fd11c Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Fri, 18 Feb 2022 19:47:22 +0900 Subject: [PATCH 18/22] Respect :suppress-verbose-errors true --- src/pogonos/api.clj | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index f613e09..9db84ad 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -38,20 +38,16 @@ (def ^:private ^:dynamic *errors*) -(defn- with-error-handling - ([opts f] (with-error-handling nil opts f)) - ([source opts f] - (try - (f) - (catch Exception e - (if (::error/type (ex-data e)) - (do (when-not (:quiet opts) - (binding [*out* *err* - error/*source* source] - (print "[ERROR] ") - (pg/perr e))) - (set! *errors* (conj *errors* e))) - (throw e)))))) +(defn- with-error-handling [opts f] + (try + (f) + (catch Exception e + (if (::error/type (ex-data e)) + (do (when-not (:quiet opts) + (binding [*out* *err*] + (println "[ERROR]" (ex-message e)))) + (set! *errors* (conj *errors* e))) + (throw e))))) (defn- check-inputs [inputs {:keys [include-regex exclude-regex] :as opts}] (let [include? (if include-regex @@ -66,8 +62,8 @@ (binding [*out* *err*] (println "Checking template" name))) (with-open [r (reader/->reader input)] - (with-error-handling name opts - #(pg/check-input r opts)))))) + (with-error-handling opts + #(pg/check-input r (assoc opts :source name))))))) (defn- check-files [files opts] (-> (for [file files From 9fe74cd1173ac3052c0ff9ad7645076c0ee4c12a Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Fri, 18 Feb 2022 22:32:47 +0900 Subject: [PATCH 19/22] Add :only-show-errors option --- src/pogonos/api.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 9db84ad..5fc1bd3 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -43,7 +43,7 @@ (f) (catch Exception e (if (::error/type (ex-data e)) - (do (when-not (:quiet opts) + (do (when (or (not (:quiet opts)) (:only-show-errors opts)) (binding [*out* *err*] (println "[ERROR]" (ex-message e)))) (set! *errors* (conj *errors* e))) @@ -58,7 +58,7 @@ (constantly false))] (doseq [{:keys [name input]} inputs :when (and (include? name) (not (exclude? name)))] - (when-not (:quiet opts) + (when (and (not (:quiet opts)) (not (:only-show-errors opts))) (binding [*out* *err*] (println "Checking template" name))) (with-open [r (reader/->reader input)] From 5ed85ff23c83be526dd0290595a7147b5858e1fa Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Sat, 19 Feb 2022 18:34:19 +0900 Subject: [PATCH 20/22] Add tests for api ns --- test-resources/data.edn | 1 + test-resources/templates/hello.mustache | 1 + test/pogonos/api_test.clj | 122 ++++++++++++++++++++++++ test/pogonos/test_runner.cljc | 2 + 4 files changed, 126 insertions(+) create mode 100644 test-resources/data.edn create mode 100644 test-resources/templates/hello.mustache create mode 100644 test/pogonos/api_test.clj diff --git a/test-resources/data.edn b/test-resources/data.edn new file mode 100644 index 0000000..5c26bc2 --- /dev/null +++ b/test-resources/data.edn @@ -0,0 +1 @@ +{:name "Clojurian"} diff --git a/test-resources/templates/hello.mustache b/test-resources/templates/hello.mustache new file mode 100644 index 0000000..963eab9 --- /dev/null +++ b/test-resources/templates/hello.mustache @@ -0,0 +1 @@ +Hello, {{name}}! diff --git a/test/pogonos/api_test.clj b/test/pogonos/api_test.clj new file mode 100644 index 0000000..064a9f2 --- /dev/null +++ b/test/pogonos/api_test.clj @@ -0,0 +1,122 @@ +(ns pogonos.api-test + (:require [clojure.java.io :as io] + [clojure.test :refer [deftest is are testing]] + [pogonos.api :as api] + [clojure.string :as str])) + +(defn test-file [path] + (str (io/file (io/resource path)))) + +(deftest render-test + (are [opts expected] (= expected (with-out-str (api/render opts))) + {:string "Hello, {{name}}!" :data {:name "Clojurian"}} + "Hello, Clojurian!" + + {:file (test-file "templates/hello.mustache") + :data-file (test-file "data.edn")} + "Hello, Clojurian!\n" + + {:resource "templates/hello.mustache" :data {:name "Clojurian"}} + "Hello, Clojurian!\n") + (is (= "Hello, Clojurian!" + (with-out-str + (with-in-str "Hello, {{name}}!" + (api/render {:data {:name "Clojurian"}})))))) + +(defn- with-stderr-lines [f] + (-> (with-out-str + (binding [*err* *out*] + (f))) + (str/split #"\n"))) + +(defn- join-paths [& paths] + (str/join (System/getProperty "path.separator") paths)) + +(deftest check-test + (testing "basic use cases" + (is (nil? (api/check {:string "{{foo}}" :quiet true}))) + (is (thrown? Exception + (api/check {:string "{{foo" :quiet true :on-failure :throw}))) + (is (nil? (api/check {:file (test-file "templates/hello.mustache") + :quiet true}))) + (is (thrown? Exception + (api/check {:file (test-file "templates/broken.mustache") + :quiet true :on-failure :throw}))) + (is (nil? (api/check {:resource "templates/hello.mustache" :quiet true}))) + (is (thrown? Exception + (api/check {:resource "templates/broken.mustache" + :quiet true :on-failure :throw}))) + (is (nil? (with-in-str "{{foo}}" (api/check {:quiet true})))) + (is (thrown? Exception + (with-in-str "{{foo" + (api/check {:quiet true :on-failure :throw}))))) + (testing "bulk check" + (testing "files" + (is (= [(str "Checking template " (test-file "templates/hello.mustache")) + (str "Checking template " (test-file "templates/main.mustache"))] + (with-stderr-lines + #(api/check {:file [(test-file "templates/hello.mustache") + (test-file "templates/main.mustache")]})))) + (let [lines (with-stderr-lines + #(api/check {:file (join-paths + (test-file "templates/hello.mustache") + (test-file "templates/broken.mustache")) + :on-failure nil + :suppress-verbose-errors true}))] + (is (= (count lines) 3)) + (is (= (str "Checking template " (test-file "templates/hello.mustache")) + (nth lines 0))) + (is (= (str "Checking template " (test-file "templates/broken.mustache")) + (nth lines 1))) + (is (str/starts-with? (nth lines 2) "[ERROR]")))) + (testing "resources" + (is (= ["Checking template templates/main.mustache" + "Checking template templates/node.mustache"] + (with-stderr-lines + #(api/check {:resource ["templates/main.mustache" + "templates/node.mustache"]})))) + (let [lines (with-stderr-lines + #(api/check {:resource (join-paths "templates/broken.mustache" + "templates/hello.mustache") + :on-failure nil + :suppress-verbose-errors true}))] + (is (= (count lines) 3)) + (is (= "Checking template templates/broken.mustache" (nth lines 0))) + (is (str/starts-with? (nth lines 1) "[ERROR]")) + (is (= "Checking template templates/hello.mustache" (nth lines 2))))) + (testing "dirs" + (let [lines (sort + (with-stderr-lines + #(api/check {:dir (test-file "templates") + :on-failure nil + :suppress-verbose-errors true})))] + (is (= [(str "Checking template " (test-file "templates/broken.mustache")) + (str "Checking template " (test-file "templates/demo.mustache")) + (str "Checking template " (test-file "templates/hello.mustache")) + (str "Checking template " (test-file "templates/main.mustache")) + (str "Checking template " (test-file "templates/node.mustache"))] + (butlast lines))) + (is (str/starts-with? (last lines) "[ERROR]"))) + (let [lines (with-stderr-lines + #(api/check {:dir (test-file "templates") + :only-show-errors true + :on-failure nil + :suppress-verbose-errors true}))] + (is (= (count lines) 1)) + (is (str/starts-with? (first lines) "[ERROR]"))) + (let [lines (sort + (with-stderr-lines + #(api/check {:dir [(test-file "templates")] + :include-regex ["broken.mustache$" "hello.mustache$"] + :on-failure nil + :suppress-verbose-errors true})))] + (is (= [(str "Checking template " (test-file "templates/broken.mustache")) + (str "Checking template " (test-file "templates/hello.mustache"))] + (butlast lines))) + (is (str/starts-with? (last lines) "[ERROR]"))) + (is (= [(str "Checking template " (test-file "templates/hello.mustache")) + (str "Checking template " (test-file "templates/main.mustache"))] + (sort + (with-stderr-lines + #(api/check {:dir (test-file "templates") + :exclude-regex "(broken|demo|node).mustache$"})))))))) diff --git a/test/pogonos/test_runner.cljc b/test/pogonos/test_runner.cljc index 59d0c58..4ea6ac6 100644 --- a/test/pogonos/test_runner.cljc +++ b/test/pogonos/test_runner.cljc @@ -1,6 +1,7 @@ (ns pogonos.test-runner (:require [clojure.test :as t] pogonos.spec-test + #?(:clj pogonos.api-test) pogonos.core-test pogonos.output-test pogonos.parse-test @@ -11,6 +12,7 @@ (defn -main [] (t/run-tests 'pogonos.spec-test + #?(:clj 'pogonos.api-test) 'pogonos.core-test 'pogonos.output-test 'pogonos.parse-test From c1192ee31b541a3d428f54845b1a46a98370c40b Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Wed, 9 Mar 2022 00:11:27 +0900 Subject: [PATCH 21/22] Add added version to api functions --- src/pogonos/api.clj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index 5fc1bd3..bdf5b88 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -9,7 +9,9 @@ (:import [java.io File PushbackReader] [java.util.regex Pattern])) -(defn render [{:keys [string file resource data data-file output] :as opts}] +(defn render + {:added "0.2.0"} + [{:keys [string file resource data data-file output] :as opts}] (let [data (or (when data-file (with-open [r (-> (io/reader (str data-file)) PushbackReader.)] @@ -89,6 +91,7 @@ (str/split (str path) path-separator))) (defn check + {:added "0.2.0"} [{:keys [string file dir resource on-failure] :or {on-failure :exit} :as opts}] (binding [*errors* []] (cond string (with-error-handling opts #(pg/check-string string opts)) From 685159a98994be9c0a7c4c7af0989dd546702fdf Mon Sep 17 00:00:00 2001 From: Shogo Ohta Date: Wed, 16 Mar 2022 00:43:29 +0900 Subject: [PATCH 22/22] Add docstrings for API fns --- src/pogonos/api.clj | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/pogonos/api.clj b/src/pogonos/api.clj index bdf5b88..d0e2bb4 100644 --- a/src/pogonos/api.clj +++ b/src/pogonos/api.clj @@ -10,6 +10,21 @@ [java.util.regex Pattern])) (defn render + "Renders the given Mustache template. + + One of the following option can be specified as a template source: + - :string Renders the given template string + - :file Renders the specified template file + - :resource Renders the specified template resource on the classpath + + If none of these are specified, the template will be read from stdin. + + The following options can also be specified: + - :output Path to the output file. If not specified, the rendering result + will be emitted to stdout by default. + - :data Map of the values passed to the template + - :data-file If specified, reads an edn map from the file specified by that + path and pass it to the template" {:added "0.2.0"} [{:keys [string file resource data data-file output] :as opts}] (let [data (or (when data-file @@ -91,6 +106,27 @@ (str/split (str path) path-separator))) (defn check + "Checks if the given Mustache template contains any syntax error. + + The following options cab be specified as a template source: + - :string Checks the given template string + - :file Checks the specified template file + - :dir Checks the template files in the specified directory + - :resource Checks the specified template resource on the classpath + + If none of these are specified, the template will be read from stdin. + + For the :file/:dir/:resource options, two or more files/directories/resources + may be specified by delimiting them with the file path separator (i.e. ':' (colon) + on Linux/macOS and ';' (semicolon) on Windows). + + When multiple templates are checked using the :file/:dir/:resource options, + they can be filtered with the :include-regex and/or exclude-regex options. + + The verbosity of the syntax check results may be adjusted to some extent with + the following options: + - :only-show-errors Hides progress messages + - :suppress-verbose-errors Suppresses verbose error messages" {:added "0.2.0"} [{:keys [string file dir resource on-failure] :or {on-failure :exit} :as opts}] (binding [*errors* []]