From d9ce43f8c490c97092422a14579d4b0df0e61240 Mon Sep 17 00:00:00 2001 From: Matus Lestan Date: Sat, 7 May 2016 14:41:11 +0200 Subject: [PATCH 1/8] Fixed mistake in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c1a80da..42c2347 100755 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ print.foo=> (use 'print.foo) nil print.foo=> (+ 1 2 (print-and-return "ONE:: " (inc 4))) -ONE:: 4 -7 +ONE:: 5 +8 print.foo> (- 1000 (tap "RESULT:: " (+ 1 2 (inc 4)))) *** RESULT:: 8 From 4e1e92f1b3a2efc4eea9adef4d7735547d50a533 Mon Sep 17 00:00:00 2001 From: madvas Date: Sat, 7 May 2016 22:14:05 +0200 Subject: [PATCH 2/8] Added Clojurescript support and some minor edits --- .gitignore | 3 + Makefile | 4 - README.md | 121 ++++++--------- project.clj | 17 +-- src/print/foo.clj | 302 -------------------------------------- src/print/foo.cljc | 315 ++++++++++++++++++++++++++++++++++++++++ test/print/test/foo.clj | 5 +- 7 files changed, 374 insertions(+), 393 deletions(-) delete mode 100644 Makefile delete mode 100644 src/print/foo.clj create mode 100644 src/print/foo.cljc diff --git a/.gitignore b/.gitignore index ee508f7..9671670 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +/.nrepl-port +/.idea +/print-foo.iml /target /lib /classes diff --git a/Makefile b/Makefile deleted file mode 100644 index b6a23f4..0000000 --- a/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -.PHONY: deploy - -deploy: - lein deploy clojars diff --git a/README.md b/README.md index 42c2347..56eadaf 100755 --- a/README.md +++ b/README.md @@ -1,101 +1,75 @@ -## print-foo +## print-foo-cljs + +This is fork of [print-foo](https://github.com/AlexBaranosky/print-foo). I added Clojurescript support and did some other edits. A Clojure library of print debugging macros. Just add "print-" to the front of a normal `->>`, `->`, `let`, `defn`, `defn-`, `cond`, `if` and prints useful information. +If you're using [Cursive](https://cursive-ide.com/), I suggest creating macro or live template for prefixing `print-` or `pf/print-` + ## Leiningen ```clj -[print-foo "1.0.1"] +[print-foo-cljs "1.0.0"] ``` ## Usage +For Clojure +```clojure +(ns my-namespace + (:require [print.foo :as pf])) +``` + +For Clojurescript +```clojure +(ns my-namespace + (:require [print.foo :as pf :include-macros true])) +``` + + ```clojure print.foo=> (use 'print.foo) nil print.foo=> (+ 1 2 (print-and-return "ONE:: " (inc 4))) -ONE:: 5 -8 +ONE::5 +=> 8 print.foo> (- 1000 (tap "RESULT:: " (+ 1 2 (inc 4)))) - *** RESULT:: 8 -8 + *** RESULT::8 +=> 992 print.foo> (def a (inc 4)) print.foo> (- 1000 (+ 1 2 (look a))) - *** A:: 8 -8 + *** A:: 5 +=> 992 print.foo> (- 1000 (look (+ 1 2 (inc 4)))) *** (+ 1 2 (INC 4)):: 8 -8 +=> 992 print.foo=> (print-sexp (str (+ 3 4) (+ 5 (* 6 2)) 4)) -3 3 -4 4 (+ 3 4) 7 -5 5 -6 6 -2 2 (* 6 2) 12 (+ 5 (* 6 2)) 17 -4 4 (str (+ 3 4) (+ 5 (* 6 2)) 4) "7174" +=> "7174" - -;; `print-sexp` is a code-walking macro that replaces -;; normal code like ->, ->>, let, cond, if, -;; etc, where possible with print.foo versions, and -;; wraps every sexp in print-and-return - -print.foo=> (pprint - (macroexpand - '(print-sexp - (let [a (-> 5 - inc - inc) - bs (->> [1 2 3 4 5 6] - (map inc) - (filter odd?))] - (println (apply + a bs)))))) - -;; => -(let* - [a - (print.foo/print-and-return 'a " " (print.foo/print-> 5 inc inc)) - bs - (print.foo/print-and-return - 'bs - " " - (print.foo/print->> [1 2 3 4 5 6] (map inc) (filter odd?)))] - (print.foo/print-and-return - "let result: " - (do - (print.foo/print-and-return - '(println (apply + a bs)) - " " - (println - (print.foo/print-and-return - '(apply + a bs) - " " - (apply + a bs))))))) - -print.foo=> (print->> [1 2 3] (mapv inc) (mapv dec)) +print.foo=> (print-->> [1 2 3] (mapv inc) (mapv dec)) [1 2 3] [1 2 3] (mapv inc) [2 3 4] (mapv dec) [1 2 3] -[1 2 3] +=> [1 2 3] -print.foo=> (print-> 1 inc dec inc dec) +print.foo=> (print--> 1 inc dec inc dec) 1 1 inc 2 dec 1 inc 2 dec 1 -1 +=> 1 print.foo=> (print-let [a 2 b 3 c (+ a b) d (+ c 7)] c) a 2 @@ -103,7 +77,7 @@ b 3 c 5 d 12 let result: 5 -5 +=> 5 print.foo=> (print-defn f [a b] (* a b)) #'user/f @@ -111,19 +85,20 @@ print.foo=> (f 3 4) a 3 b 4 defn 'f' result: 12 -12 +=> 12 print.foo=> (print-defn- g [a b] (+ a b)) #'user/f print.foo=> (g 3 4) a 3 b 4 -defn 'g' result: 7 -7 +defn- 'g' result: 7 +=> 7 print.foo=> (print-cond nil 2 3 4) -test: 3 value: 4 -4 +test: 3 +value: 4 +=> 4 print.foo=> (print-cond-> {} (pos? 1) @@ -136,7 +111,7 @@ print.foo=> (print-cond-> {} (merge {:c 3})) test: (pos? 1) value: {:a 1} test: (pos? 2) value: {:a 1, :b 2} -{:b 2, :a 1} +=> {:a 1, :b 2} (print-cond->> [1 2 3] (pos? 1) @@ -145,12 +120,12 @@ test: (pos? 2) value: {:a 1, :b 2} (neg? 2) (map dec)) test: (pos? 1) value: (2 3 4) -(2 3 4) +=> (2 3 4) print.foo=> (print-if (odd? 9) 1 2) (odd? 9) true 1 1 -1 +=> 1 print.foo> (middleware-> {:get-in [:session] @@ -169,7 +144,7 @@ print.foo> (middleware-> (fn [y] (x (assoc y :m3 true)))) -((middleware-> {:timings? false +((middleware-> {:timings? true :get-in [:session]} m1 m2 @@ -183,20 +158,18 @@ print.foo> (middleware-> {:token 1} "REQUEST - GOING INTO: m2" {:token 1} -{:m2 true, :m3 true, :session {:token 1}} +{:session {:token 1}, :m3 true, :m2 true} "RESPONSE - COMING OUT OF: m2" {:token 1} "RESPONSE - COMING OUT OF: m3" {:token 1} +{:middleware-timings + [{:middleware "m2", :middleware-elapsed 1} + {:middleware "m3", :middleware-elapsed 3}]} +=> {:session {:token 1}, :m3 true, :m2 true} ``` -## Author - -* [Alex Baranosky](https://github.com/AlexBaranosky) - ## License -Copyright © 2013 Alex Baranosky - Distributed under the MIT License diff --git a/project.clj b/project.clj index d5f62ba..665472f 100755 --- a/project.clj +++ b/project.clj @@ -1,11 +1,8 @@ -(defproject print-foo "1.0.2" - :description "A set of useful print-debugging tools" - :url "https://github.com/AlexBaranosky/print-foo" +(defproject print-foo-cljs "1.0.0" + :description "A set of useful print-debugging tools for both Clojure & Clojurescript" + :url "https://github.com/madvas/print-foo-cljs" :license {:name "MIT License" - :url "http://mit-license.org/"} - :dependencies [[org.clojure/clojure "1.5.1"] - [gui-diff "0.6.6"]] - :profiles {:dev {:dependencies [[org.clojars.runa/conjure "2.2.0"]] - :plugins [[jonase/eastwood "0.0.2"]]}} - :deploy-repositories [["clojars" {:url "https://clojars.org/repo/" - :sign-releases false}]]) + :url "http://mit-license.org/"} + :dependencies [[org.clojure/clojure "1.8.0"]] + :profiles {:dev {:dependencies [] + :plugins []}}) diff --git a/src/print/foo.clj b/src/print/foo.clj deleted file mode 100644 index 13d85bc..0000000 --- a/src/print/foo.clj +++ /dev/null @@ -1,302 +0,0 @@ -(ns print.foo - "Macros for printing diagnostic information while debugging or developing." - (:require [clojure.string :as str] - [gui.diff :as gui-diff])) - - -(defn- single-destructuring-arg->form+name - "Turns any one binding arg (which may be a destructuring binding) into a vector - where the left elem is the arg with a possible :as added to it. - And the rght side is the symbol referring to the arg itself." - [arg-form] - (let [as-symbol (gensym 'symbol-for-destructured-arg) - snd-to-last-is-as? #(= :as (second (reverse %)))] - (cond (and (vector? arg-form) (snd-to-last-is-as? arg-form)) - [arg-form (last arg-form)] - - (vector? arg-form) - [(-> arg-form (conj :as) (conj as-symbol)) as-symbol] - - (and (map? arg-form) (contains? arg-form :as)) - [arg-form (:as arg-form)] - - (map? arg-form) - [(assoc arg-form :as as-symbol) as-symbol] - - :else - [arg-form arg-form]))) - -(defn- expand-arg [arg] - (if (symbol? arg) - arg - (first (single-destructuring-arg->form+name arg)))) - -(defn print-and-return - "Diagnostic tool for printing the result of evaluating an s-expression. - Any initial args over 1, are printed as strings, and generally used as a label." - [& xs] - (when (seq (butlast xs)) - (print (apply str (butlast xs)))) - (gui-diff/p (last xs)) - (last xs)) - -(def tap - "Quicker-to-type version of `print-and-return` with \" *** \" appended to the front" - (partial print-and-return " *** ")) - -(defmacro look - "Like print-and-return, except always prefixes with the uppercased sexp followed by ':: '" - [sexp] - `(tap ~(str/upper-case (str sexp ":: ")) - ~sexp)) - -(defmacro print-> - "Diagnostic tool for printing the values at each step of a `->`" - [& body] - (let [print-forms (map #(list `(fn [x#] (print-and-return '~% " " x#))) body)] - (cons '-> (interleave body print-forms)))) - -(defmacro print->> - "Diagnostic tool for printing the values at each step of a `->>`" - [& body] - (let [print-forms (map (fn [x] `(print-and-return '~x " ")) body)] - (cons '->> (interleave body print-forms)))) - -(defmacro print-let - "Diagnostic tool for printing the values at each step of a `let`" - [bindings & body] - (let [firsts (take-nth 2 bindings) - seconds (take-nth 2 (rest bindings))] - `(let ~(vec (interleave firsts - (map (fn [lhs rhs] - `(print-and-return '~lhs " " ~rhs)) - firsts - seconds))) - (print-and-return "let result: " (do ~@body))))) - -(defmacro print-if - "Diagnostic tool for printing the values at each step of an `if`" - [test expr1 expr2] - `(if (print-and-return '~test " " ~test) - (print-and-return '~expr1 " " ~expr1) - (print-and-return '~expr2 " " ~expr2))) - -(defmacro print-cond - "Diagnostic tool for printing the values at each step of a `cond`" - [& body] - (cons 'cond (for [[test expr] (partition 2 body) - sym [test `(print-and-return "test: " '~test "\nvalue: " ~expr)]] - sym))) - -(defmacro print-cond-> - "Diagnostic tool for printing the values at each step of a `cond->`" - [& body] - (cons 'cond-> - (cons (first body) - (for [[test expr] (partition 2 (rest body)) - sym [test `((fn [x#] - (print-and-return "test: " '~test - " value: " (~(first expr) - x# - ~@(rest expr)))))]] - sym)))) - -(defmacro print-cond->> - "Diagnostic tool for printing the values at each step of a `cond->>`" - [& body] - (cons 'cond->> - (cons (first body) - (for [[test expr] (partition 2 (rest body)) - sym [test `((fn [x#] - (print-and-return "test: " '~test - " value: " (~(first expr) - ~@(rest expr) - x#))))]] - sym)))) - -(defmacro print-defn - "Diagnostic tool for printing the values at each step of a `defn`" - [fn-name arg-vec & body] - (let [new-arg-vec (vec (map expand-arg arg-vec))] - `(defn ~fn-name ~new-arg-vec - ~@(keep (fn [x] - (cond (and (not= '& x) (symbol? x)) - `(print-and-return '~x " " ~x) - - (not= '& x) - (let [[form as] (single-destructuring-arg->form+name x)] - `(print-and-return '~x " " ~as)))) - new-arg-vec) - nil - (print-and-return "defn '" '~fn-name "' result: " (do ~@body))))) - -(defmacro print-defn- - "Diagnostic tool for printing the values at each step of a `defn-`" - [fn-name arg-vec & body] - (let [new-arg-vec (vec (map expand-arg arg-vec))] - `(defn- ~fn-name ~new-arg-vec - ~@(keep (fn [x] - (cond (and (not= '& x) (symbol? x)) - `(print-and-return '~x " " ~x) - - (not= '& x) - (let [[form as] (single-destructuring-arg->form+name x)] - `(print-and-return '~x " " ~as)))) - new-arg-vec) - nil - (print-and-return "defn- '" '~fn-name "' result: " (do ~@body))))) - - -;;; `print-sexp` print.foo's code-walking macro :) - -(defn- resolves-to-fn? [x] - (boolean (some-> x resolve deref fn?))) - -(defmulti parse-item (fn [x] - (cond (list? x) :list - (vector? x) :vector - (set? x) :set - (map? x) :map - (and (symbol? x) - (not (resolves-to-fn? x))) :sym - :else :default))) - -(defmulti parse-list (fn [[sym & _]] - sym)) - - -(defmethod parse-item :list [lst] - (parse-list lst)) - -(defmethod parse-item :vector [v] - (into (empty v) (map parse-item v))) - -(defmethod parse-item :set [s] - (into (empty s) (map parse-item s))) - -(defmethod parse-item :map [m] - (into (empty m) - (for [[k v] m] - [(parse-item k) (parse-item v)]))) - -(defmethod parse-item :sym [s] - `(print-and-return '~s " " ~s)) - -(defmethod parse-item :default [x] - x) - - -(defmethod parse-list '-> [[_ & args]] - `(print-> ~@args)) - -(defmethod parse-list '->> [[_ & args]] - `(print->> ~@args)) - -(defmethod parse-list 'cond-> [[_ & args]] - `(print-cond-> ~@args)) - -(defmethod parse-list 'cond->> [[_ & args]] - `(print-cond->> ~@args)) - - -(defmethod parse-list 'let [[_ & [bindings & body]]] - (let [bdg-names (take-nth 2 bindings) - bdg-vals (take-nth 2 (rest bindings))] - `(print-let ~(vec (interleave bdg-names - (map parse-item bdg-vals))) - ~@(map parse-item body)))) - -(defmethod parse-list 'if [[_ & args]] - `(print-if ~@(map parse-item args))) - -(defmethod parse-list 'cond [[_ & args]] - `(cond ~@(map parse-item args))) - -(defmethod parse-list 'defn [[_ & args]] - `(print-defn ~@args)) - -(defmethod parse-list 'defn- [[_ & args]] - `(print-defn- ~@args)) - -(defmethod parse-list :default [[sym & args]] - (let [l (concat [sym] args)] - `(print-and-return - '~l - " " - ~(map (fn [idx x] - (if (zero? idx) - x - (parse-item x))) - (range) - l)))) - -(defmacro print-sexp - "Diagnostic tool for printing the values at each step of a given s-expression" - [sexp] - (parse-item sexp)) - -(defn wrap-middleware-debugging - [handler middleware-name {:keys [get-in summarize? timings?] - :or {get-in [] - summarize? true - timings? false}}] - (fn [request] - (print-and-return (str "REQUEST - GOING INTO: " middleware-name)) - (print-and-return (clojure.core/get-in request get-in)) - (let [start (System/currentTimeMillis) - result (handler request) - end (System/currentTimeMillis) - result (-> result - (cond-> - timings? - (update-in [::timings] #(conj (or % []) - {:middleware middleware-name - :middleware-elapsed (- end start)}))))] - (print-and-return (str "RESPONSE - COMING OUT OF: " middleware-name)) - (print-and-return (clojure.core/get-in result get-in)) - (if (and timings? summarize?) - (do - (print-and-return {:middleware-timings (::timings result)}) - (dissoc result ::timings)) - result)))) - -(defn- interleave-middlewares - [handler middlewares {:keys [get-in timings?] - :or {get-in [] - timings? false}}] - (let [summarize?-determinations (conj (vec (repeat (dec (count middlewares)) - false)) - true) - mw-names (map str middlewares) - logging-mws (for [[summarize? mw-name] (map list - summarize?-determinations - mw-names)] - `(wrap-middleware-debugging ~mw-name {:summarize? ~summarize? - :get-in ~get-in - :timings? ~timings?}))] - `(-> ~handler - ~@(interleave middlewares logging-mws)))) - -(defmacro middleware-> - "Log middleware options are: - - {:get-in - :timings? - - Ex. (middleware-> - {:get-in [:session] - :timings? true}} - my-handler - wrap-exception-handling - wrap-params)" - {:arglists '([handler & middlewares] - [handler options & middlewares])} - [& options+handler+middlewares] - (if-not (map? (first options+handler+middlewares)) - (let [handler (first options+handler+middlewares) - middlewares (rest options+handler+middlewares)] - (#'interleave-middlewares handler middlewares {})) - (let [options (first options+handler+middlewares) - handler (second options+handler+middlewares) - middlewares (rest (rest options+handler+middlewares))] - (#'interleave-middlewares handler middlewares options)))) diff --git a/src/print/foo.cljc b/src/print/foo.cljc new file mode 100644 index 0000000..d85f974 --- /dev/null +++ b/src/print/foo.cljc @@ -0,0 +1,315 @@ +(ns print.foo + "Macros for printing diagnostic information while debugging or developing." + (:require + [clojure.string :as str] + #?(:clj + [clojure.pprint :as pp] + :cljs [cljs.pprint :as pp]))) + + +(defn ^:private single-destructuring-arg->form+name + "Turns any one binding arg (which may be a destructuring binding) into a vector + where the left elem is the arg with a possible :as added to it. + And the rght side is the symbol referring to the arg itself." + [arg-form] + (let [as-symbol (gensym 'symbol-for-destructured-arg) + snd-to-last-is-as? #(= :as (second (reverse %)))] + (cond (and (vector? arg-form) (snd-to-last-is-as? arg-form)) + [arg-form (last arg-form)] + + (vector? arg-form) + [(-> arg-form (conj :as) (conj as-symbol)) as-symbol] + + (and (map? arg-form) (contains? arg-form :as)) + [arg-form (:as arg-form)] + + (map? arg-form) + [(assoc arg-form :as as-symbol) as-symbol] + + :else + [arg-form arg-form]))) + +(defn ^:private expand-arg [arg] + (if (symbol? arg) + arg + (first (single-destructuring-arg->form+name arg)))) + +(defn print-and-return + "Diagnostic tool for printing the result of evaluating an s-expression. + Any initial args over 1, are printed as strings, and generally used as a label." + [& xs] + (when (seq (butlast xs)) + (print (apply str (butlast xs)))) + (pp/pprint (last xs)) + (last xs)) + +(def tap + "Quicker-to-type version of `print-and-return` with \" *** \" appended to the front" + (partial print-and-return " *** ")) + +(defn ^:private resolves-to-fn? [x] + #?(:clj (boolean (some-> x resolve deref fn?)) + :cljs true)) + +(defmulti parse-item + (fn [x] + (cond (list? x) :list + (vector? x) :vector + (set? x) :set + (map? x) :map + (and (symbol? x) + (not (resolves-to-fn? x))) :sym + :else :default))) + +(defmulti parse-list (fn [[sym & _]] + sym)) + + +(defmethod parse-item :list [lst] + (parse-list lst)) + +(defmethod parse-item :vector [v] + (into (empty v) (map parse-item v))) + +(defmethod parse-item :set [s] + (into (empty s) (map parse-item s))) + +(defmethod parse-item :map [m] + (into (empty m) + (for [[k v] m] + [(parse-item k) (parse-item v)]))) + +(defmethod parse-item :sym [s] + `(print-and-return '~s " " ~s)) + +(defmethod parse-item :default [x] + x) + + +(defmethod parse-list '-> [[_ & args]] + `(print-> ~@args)) + +(defmethod parse-list '->> [[_ & args]] + `(print->> ~@args)) + +(defmethod parse-list 'cond-> [[_ & args]] + `(print-cond-> ~@args)) + +(defmethod parse-list 'cond->> [[_ & args]] + `(print-cond->> ~@args)) + + +(defmethod parse-list 'let [[_ & [bindings & body]]] + (let [bdg-names (take-nth 2 bindings) + bdg-vals (take-nth 2 (rest bindings))] + `(print-let ~(vec (interleave bdg-names + (map parse-item bdg-vals))) + ~@(map parse-item body)))) + +(defmethod parse-list 'if [[_ & args]] + `(print-if ~@(map parse-item args))) + +(defmethod parse-list 'cond [[_ & args]] + `(cond ~@(map parse-item args))) + +(defmethod parse-list 'defn [[_ & args]] + `(print-defn ~@args)) + +(defmethod parse-list 'defn- [[_ & args]] + `(print-defn- ~@args)) + +(defmethod parse-list :default [[sym & args]] + (let [l (concat [sym] args)] + `(print-and-return + '~l + " " + ~(map (fn [idx x] + (if (zero? idx) + x + (parse-item x))) + (range) + l)))) + +(defn get-miliseconds [] + #?(:clj (System/currentTimeMillis) + :cljs (.getMilliseconds (new js/Date)))) + +(defn wrap-middleware-debugging + [handler middleware-name {:keys [get-in summarize? timings?] + :or {get-in [] + summarize? true + timings? false}}] + (fn [request] + (print-and-return (str "REQUEST - GOING INTO: " middleware-name)) + (print-and-return (clojure.core/get-in request get-in)) + (let [start (get-miliseconds) + result (handler request) + end (get-miliseconds) + result (-> result + (cond-> + timings? + (update-in [::timings] #(conj (or % []) + {:middleware middleware-name + :middleware-elapsed (- end start)}))))] + (print-and-return (str "RESPONSE - COMING OUT OF: " middleware-name)) + (print-and-return (clojure.core/get-in result get-in)) + (if (and timings? summarize?) + (do + (print-and-return {:middleware-timings (::timings result)}) + (dissoc result ::timings)) + result)))) + +(defn ^:private interleave-middlewares + [handler middlewares {:keys [get-in timings?] + :or {get-in [] + timings? false}}] + (let [summarize?-determinations (conj (vec (repeat (dec (count middlewares)) + false)) + true) + mw-names (map str middlewares) + logging-mws (for [[summarize? mw-name] (map list + summarize?-determinations + mw-names)] + `(wrap-middleware-debugging ~mw-name {:summarize? ~summarize? + :get-in ~get-in + :timings? ~timings?}))] + `(-> ~handler + ~@(interleave middlewares logging-mws)))) + + +#?(:clj + (do + (defmacro look + "Like print-and-return, except always prefixes with the uppercased sexp followed by ':: '" + [sexp] + `(tap ~(str/upper-case (str sexp ":: ")) + ~sexp)) + + (defmacro print--> + "Diagnostic tool for printing the values at each step of a `->`" + [& body] + (let [print-forms (map #(list `(fn [x#] (print-and-return '~% " " x#))) body)] + (cons '-> (interleave body print-forms)))) + + (defmacro print-->> + "Diagnostic tool for printing the values at each step of a `->>`" + [& body] + (let [print-forms (map (fn [x] `(print-and-return '~x " ")) body)] + (cons '->> (interleave body print-forms)))) + + (defmacro print-let + "Diagnostic tool for printing the values at each step of a `let`" + [bindings & body] + (let [firsts (take-nth 2 bindings) + seconds (take-nth 2 (rest bindings))] + `(let ~(vec (interleave firsts + (map (fn [lhs rhs] + `(print-and-return '~lhs " " ~rhs)) + firsts + seconds))) + (print-and-return "let result: " (do ~@body))))) + + (defmacro print-if + "Diagnostic tool for printing the values at each step of an `if`" + [test expr1 expr2] + `(if (print-and-return '~test " " ~test) + (print-and-return '~expr1 " " ~expr1) + (print-and-return '~expr2 " " ~expr2))) + + (defmacro print-cond + "Diagnostic tool for printing the values at each step of a `cond`" + [& body] + (cons 'cond (for [[test expr] (partition 2 body) + sym [test `(print-and-return "test: " '~test "\nvalue: " ~expr)]] + sym))) + + (defmacro print-cond-> + "Diagnostic tool for printing the values at each step of a `cond->`" + [& body] + (cons 'cond-> + (cons (first body) + (for [[test expr] (partition 2 (rest body)) + sym [test `((fn [x#] + (print-and-return "test: " '~test + " value: " (~(first expr) + x# + ~@(rest expr)))))]] + sym)))) + + (defmacro print-cond->> + "Diagnostic tool for printing the values at each step of a `cond->>`" + [& body] + (cons 'cond->> + (cons (first body) + (for [[test expr] (partition 2 (rest body)) + sym [test `((fn [x#] + (print-and-return "test: " '~test + " value: " (~(first expr) + ~@(rest expr) + x#))))]] + sym)))) + + (defmacro print-defn + "Diagnostic tool for printing the values at each step of a `defn`" + [fn-name arg-vec & body] + (let [new-arg-vec (vec (map expand-arg arg-vec))] + `(defn ~fn-name ~new-arg-vec + ~@(keep (fn [x] + (cond (and (not= '& x) (symbol? x)) + `(print-and-return '~x " " ~x) + + (not= '& x) + (let [[form as] (single-destructuring-arg->form+name x)] + `(print-and-return '~x " " ~as)))) + new-arg-vec) + nil + (print-and-return "defn '" '~fn-name "' result: " (do ~@body))))) + + (defmacro print-defn- + "Diagnostic tool for printing the values at each step of a `defn-`" + [fn-name arg-vec & body] + (let [new-arg-vec (vec (map expand-arg arg-vec))] + `(defn- ~fn-name ~new-arg-vec + ~@(keep (fn [x] + (cond (and (not= '& x) (symbol? x)) + `(print-and-return '~x " " ~x) + + (not= '& x) + (let [[form as] (single-destructuring-arg->form+name x)] + `(print-and-return '~x " " ~as)))) + new-arg-vec) + nil + (print-and-return "defn- '" '~fn-name "' result: " (do ~@body))))) + + + ;;; `print-sexp` print.foo's code-walking macro :) + + (defmacro print-sexp + "Diagnostic tool for printing the values at each step of a given s-expression" + [sexp] + (parse-item sexp)) + + (defmacro middleware-> + "Log middleware options are: + + {:get-in + :timings? + + Ex. (middleware-> + {:get-in [:session] + :timings? true}} + my-handler + wrap-exception-handling + wrap-params)" + {:arglists '([handler & middlewares] + [handler options & middlewares])} + [& options+handler+middlewares] + (if-not (map? (first options+handler+middlewares)) + (let [handler (first options+handler+middlewares) + middlewares (rest options+handler+middlewares)] + (#'interleave-middlewares handler middlewares {})) + (let [options (first options+handler+middlewares) + handler (second options+handler+middlewares) + middlewares (rest (rest options+handler+middlewares))] + (#'interleave-middlewares handler middlewares options)))) + )) \ No newline at end of file diff --git a/test/print/test/foo.clj b/test/print/test/foo.clj index 1ea918c..3b55066 100644 --- a/test/print/test/foo.clj +++ b/test/print/test/foo.clj @@ -1,7 +1,6 @@ (ns print.test.foo - (:require [print.foo :refer :all] - [clojure.test :refer :all] - [conjure.core :refer :all])) + (:use [print.foo] + [clojure.test])) (print-defn a []) (print-defn b [x y] (+ x y)) From f6bebf63ca8832fa4d42f07d8cb0b35e7acaf7cb Mon Sep 17 00:00:00 2001 From: madvas Date: Sat, 7 May 2016 22:26:21 +0200 Subject: [PATCH 3/8] Added Clojurescript support and some minor edits --- .gitignore | 1 + test/print/test/foo.clj | 46 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/.gitignore b/.gitignore index 9671670..c787c65 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/pom.xml.asc /.nrepl-port /.idea /print-foo.iml diff --git a/test/print/test/foo.clj b/test/print/test/foo.clj index 3b55066..4c5483d 100644 --- a/test/print/test/foo.clj +++ b/test/print/test/foo.clj @@ -40,3 +40,49 @@ (d2 [3 7]) (f2 3 [7] {:d 11}) (g2 3 [7] {:d 11})) + + + +(comment + (use 'print.foo) + (:require-macros [print.foo :refer [print-and-return tap look print-> print-sexp print->> print-> print-let print-defn print-cond + print-cond-> print-cond->> print-if middleware->]]) + + (+ 1 2 (print-and-return "ONE::" (inc 4))) + (- 1000 (tap "RESULT::" (+ 1 2 (inc 4)))) + (do (def a (inc 4)) + (- 1000 (+ 1 2 (look a)))) + (- 1000 (look (+ 1 2 (inc 4)))) + (print-sexp (str (+ 3 4) (+ 5 (* 6 2)) 4)) + (print-->> [1 2 3] (mapv inc) (mapv dec)) + (print--> 1 inc dec inc dec) + (print-let [a 2 b 3 c (+ a b) d (+ c 7)] c) + (do (print-defn f [a b] (* a b)) + (f 3 4)) + (print-cond nil 2 3 4) + (print-cond-> {} + (pos? 1) (assoc :a 1) + (pos? 2) (merge {:b 2}) + (neg? 2) (merge {:c 3})) + (print-cond->> [1 2 3] + (pos? 1) (map inc) + (neg? 2) (map dec)) + (print-if (odd? 9) 1 2) + + (do (defn m1 [x] + (println x) + x) + (defn m2 [x] + (fn [y] + (x (assoc y :m2 true)))) + (defn m3 [x] + (fn [y] + (x (assoc y :m3 true)))) + + ((middleware-> {:timings? true + :get-in [:session]} + m1 + m2 + m3) + + {:session {:token 1}}))) \ No newline at end of file From dfb914e001a67a27551a0aa1008013df6af09b3a Mon Sep 17 00:00:00 2001 From: madvas Date: Sat, 7 May 2016 22:29:05 +0200 Subject: [PATCH 4/8] version bump --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 665472f..6ad5fc0 100755 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject print-foo-cljs "1.0.0" +(defproject print-foo-cljs "2.0.0" :description "A set of useful print-debugging tools for both Clojure & Clojurescript" :url "https://github.com/madvas/print-foo-cljs" :license {:name "MIT License" From 11c4e46518d468fce83d7125b211a9138399cf83 Mon Sep 17 00:00:00 2001 From: madvas Date: Sat, 7 May 2016 22:30:20 +0200 Subject: [PATCH 5/8] version bump --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56eadaf..55ce821 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ If you're using [Cursive](https://cursive-ide.com/), I suggest creating macro or ## Leiningen ```clj -[print-foo-cljs "1.0.0"] +[print-foo-cljs "2.0.0"] ``` ## Usage From 7998210105bfdfa70e15357c89400ad0b4875665 Mon Sep 17 00:00:00 2001 From: madvas Date: Sat, 20 Aug 2016 11:34:44 +0200 Subject: [PATCH 6/8] Making pretty print function dynamic --- README.md | 2 +- project.clj | 2 +- src/print/foo.cljc | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 55ce821..14ca29f 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ If you're using [Cursive](https://cursive-ide.com/), I suggest creating macro or ## Leiningen ```clj -[print-foo-cljs "2.0.0"] +[print-foo-cljs "2.0.1"] ``` ## Usage diff --git a/project.clj b/project.clj index 6ad5fc0..6abc57d 100755 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject print-foo-cljs "2.0.0" +(defproject print-foo-cljs "2.0.1" :description "A set of useful print-debugging tools for both Clojure & Clojurescript" :url "https://github.com/madvas/print-foo-cljs" :license {:name "MIT License" diff --git a/src/print/foo.cljc b/src/print/foo.cljc index d85f974..711d5c0 100644 --- a/src/print/foo.cljc +++ b/src/print/foo.cljc @@ -6,6 +6,7 @@ [clojure.pprint :as pp] :cljs [cljs.pprint :as pp]))) +(def ^:dynamic *print-fn* pp/pprint) (defn ^:private single-destructuring-arg->form+name "Turns any one binding arg (which may be a destructuring binding) into a vector @@ -40,7 +41,7 @@ [& xs] (when (seq (butlast xs)) (print (apply str (butlast xs)))) - (pp/pprint (last xs)) + (*print-fn* (last xs)) (last xs)) (def tap From f4a61bba110b034a5fa0fd2b7000980375547e08 Mon Sep 17 00:00:00 2001 From: madvas Date: Sat, 20 Aug 2016 16:36:04 +0200 Subject: [PATCH 7/8] Added dynamic variable to disable all printing --- README.md | 2 +- project.clj | 2 +- src/print/foo.cljc | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 14ca29f..b3ddc3c 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ If you're using [Cursive](https://cursive-ide.com/), I suggest creating macro or ## Leiningen ```clj -[print-foo-cljs "2.0.1"] +[print-foo-cljs "2.0.2"] ``` ## Usage diff --git a/project.clj b/project.clj index 6abc57d..e59d4b2 100755 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject print-foo-cljs "2.0.1" +(defproject print-foo-cljs "2.0.2" :description "A set of useful print-debugging tools for both Clojure & Clojurescript" :url "https://github.com/madvas/print-foo-cljs" :license {:name "MIT License" diff --git a/src/print/foo.cljc b/src/print/foo.cljc index 711d5c0..38d8f00 100644 --- a/src/print/foo.cljc +++ b/src/print/foo.cljc @@ -7,6 +7,7 @@ :cljs [cljs.pprint :as pp]))) (def ^:dynamic *print-fn* pp/pprint) +(def ^:dynamic *enabled* true) (defn ^:private single-destructuring-arg->form+name "Turns any one binding arg (which may be a destructuring binding) into a vector @@ -39,9 +40,10 @@ "Diagnostic tool for printing the result of evaluating an s-expression. Any initial args over 1, are printed as strings, and generally used as a label." [& xs] - (when (seq (butlast xs)) - (print (apply str (butlast xs)))) - (*print-fn* (last xs)) + (when *enabled* + (when (seq (butlast xs)) + (print (apply str (butlast xs)))) + (*print-fn* (last xs))) (last xs)) (def tap From 919a803fd4ea7362f7d706385930233c52aa9f74 Mon Sep 17 00:00:00 2001 From: madvas Date: Fri, 2 Sep 2016 14:18:40 +0200 Subject: [PATCH 8/8] Added preloads --- README.md | 2 +- project.clj | 5 +++-- src/print/foo.cljc | 1 + src/print/foo/preloads/devtools.cljs | 9 +++++++++ src/print/foo/preloads/require.cljs | 4 ++++ 5 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 src/print/foo/preloads/devtools.cljs create mode 100644 src/print/foo/preloads/require.cljs diff --git a/README.md b/README.md index b3ddc3c..84b429f 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ If you're using [Cursive](https://cursive-ide.com/), I suggest creating macro or ## Leiningen ```clj -[print-foo-cljs "2.0.2"] +[print-foo-cljs "2.0.3"] ``` ## Usage diff --git a/project.clj b/project.clj index e59d4b2..7359857 100755 --- a/project.clj +++ b/project.clj @@ -1,8 +1,9 @@ -(defproject print-foo-cljs "2.0.2" +(defproject print-foo-cljs "2.0.3" :description "A set of useful print-debugging tools for both Clojure & Clojurescript" :url "https://github.com/madvas/print-foo-cljs" :license {:name "MIT License" :url "http://mit-license.org/"} - :dependencies [[org.clojure/clojure "1.8.0"]] + :dependencies [[org.clojure/clojure "1.8.0"] + [binaryage/devtools "0.8.1"]] :profiles {:dev {:dependencies [] :plugins []}}) diff --git a/src/print/foo.cljc b/src/print/foo.cljc index 38d8f00..3b15d2d 100644 --- a/src/print/foo.cljc +++ b/src/print/foo.cljc @@ -1,5 +1,6 @@ (ns print.foo "Macros for printing diagnostic information while debugging or developing." + (:refer-clojure :exclude [*print-fn*]) (:require [clojure.string :as str] #?(:clj diff --git a/src/print/foo/preloads/devtools.cljs b/src/print/foo/preloads/devtools.cljs new file mode 100644 index 0000000..7b54823 --- /dev/null +++ b/src/print/foo/preloads/devtools.cljs @@ -0,0 +1,9 @@ +(ns print.foo.preloads.devtools + (:require [devtools.preload] + [print.foo :include-macros true])) + +(enable-console-print!) + +(set! print.foo/*print-fn* (aget js/console "log")) + + diff --git a/src/print/foo/preloads/require.cljs b/src/print/foo/preloads/require.cljs new file mode 100644 index 0000000..ea31ee5 --- /dev/null +++ b/src/print/foo/preloads/require.cljs @@ -0,0 +1,4 @@ +(ns print.foo.preloads.require + (:require [print.foo :include-macros true])) + +(enable-console-print!) \ No newline at end of file