Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

explain-console to provide devtools friendly console output (CLJS) #2

Open
olivergeorge opened this issue Jul 21, 2016 · 10 comments
Open

Comments

@olivergeorge
Copy link

olivergeorge commented Jul 21, 2016

Hi

Not sure if it's your intend for this to cover both CLJ and CLJS but one early pain point for CLJS is the printing of large datastructures as part of explain-out.

Using Google Chrome and cljs-devtools gives us custom formatters on the console which means we can drill down into maps/vectors, see pretty printed keywords etc. Big step forward!

This is a totally hacky port which vaguely does as described:

(defn explain-console
  "print an explanation to js/console.log"
  [ed]
  (let [print (fn [& args] (.apply (.-log js/console) js/console (to-array args)))]
    (if ed
      (do
        (doseq [[path {:keys [pred val reason via in] :as prob}] (::s/problems ed)]
          (when-not (empty? in)
            (print "In:" in ""))
          (print " val: " val)
          (when-not (empty? via)
            (print " fails spec:" (last via)))
          (when-not (empty? path)
            (print " at:" path))
          (print " predicate: " pred)
          (when reason (print ", " reason))
          (doseq [[k v] prob]
            (when-not (#{:pred :val :reason :via :in} k)
              (print k " " v))))
        (doseq [[k v] ed]
          (when-not (#{::s/problems} k)
            (print k " " v))))
      (println "Success!"))))
@gfredericks
Copy link
Owner

CLJS is definitely in-scope. This seems like something that could go in com.gfredericks.schpec, and we could change that to be a cljc file.

Could this be reasonably tested? I suppose by setting up testing via node the same as in test.chuck?

@olivergeorge
Copy link
Author

It could return some structured data to avoid the need to test side effects.

@gfredericks
Copy link
Owner

what does explain normally do in cljs? (i.e., what's the problem we're trying to solve exactly?)

@olivergeorge
Copy link
Author

Context: I typically develop web applications using CLJS and re-frame / om.

The current behaviour is to throw ex-info with a message including (str
args)

(throw
  (ex-info
    (str "Call to " (pr-str v) " did not conform to spec:\n" (with-out-str
(explain-out ed)))
    ed))

A few problems arise:

  • the ex-message can fill pages on console output because the call args are
    printed via pr-str. In these cases it's difficult to read the details.
  • the work around suggested by alexmiller was to catch the exception and
    print ex-data as you see fit but that can be quite difficult in situations
    with callbacks, render loops, event dispatch queues etc.

On 28 July 2016 at 09:41, Gary Fredericks [email protected] wrote:

what does explain normally do in cljs? (i.e., what's the problem we're
trying to solve exactly?)


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#2 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGEd_ax5JAx-_gfgslU4OLBIxKAo6z_ks5qZ-yrgaJpZM4JRaWZ
.

@atroche
Copy link

atroche commented Aug 6, 2016

cljs-devtools lets you specify custom formatters by extending a protocol (IFormat):

image

But it looks like spec can only explain in the form of a string or a map.

We could have a function that returns a record that satisfies the IFormat protocol, which cljs-devtools can then use to print in its very pretty way (using Custom Object Formatters).

@atroche
Copy link

atroche commented Aug 6, 2016

It would look a little something like this:

(ns user
  (:require
    [devtools.core :as devtools]
    [devtools.protocols :as devtools-protocols]
    [devtools.formatters.templating :as template]
    [devtools.formatters.markup :as m]
    [cljs.spec :as s]))

(defrecord explain-data-record [problems]
  devtools-protocols/IFormat
  (-header [_]
    (let [paths (keys problems)]
      (template/render-markup
        [["span"] "Spec problems at " (clojure.string/join " and " paths)])))
  (-has-body [_] true)
  (-body [_]
    (template/render-markup
      (m/<list>
        (for [problem (vals problems)]
          (let [{:keys [pred val reason via in] :as prob} problem]
            (m/<string> "Insert something here")))
        (count problems)))))

(s/def ::email
  (s/and string?
         #(clojure.string/includes? % "@")))

(set! (.-onload js/window)
      (fn []
        (enable-console-print!)
        (devtools/install! [:formatters :hints])
        (let [problems (::s/problems (s/explain-data (s/keys :req [::email ::password])
                                                     {::email 123}))]
          (.log js/console (->explain-data-record problems)))))

Now what we need is to come up with a pretty representation using either raw JsonML or devtools' own markup language…

@gfredericks
Copy link
Owner

I think devtools-specific stuff should go in a special namespace, something like com.gfredericks.schpec.cljs-devtools, so people who don't depend on it can just avoid requiring that namespace.

@gfredericks
Copy link
Owner

@atroche are you saying that the original code posted here is not sufficient to get the pretty output in chrome?

After looking at it I had guessed that it was piggybacking on devtools' printing of generic clojure data structures, which would let us avoid a bunch of custom formatting code I would imagine.

@olivergeorge
Copy link
Author

I opened a related cljs-devtools issue:
binaryage/cljs-devtools#23

@darwin is looking at a cljs patch to make ExceptionInfo more "normal" so that it's amenable to formatting.

@olivergeorge
Copy link
Author

I've updated my util/patch to suit the latest cljs release (instrument things changed/moved). Here's a gist in case it's of interest.

https://gist.github.com/olivergeorge/d73fa855b40f6c8592a37dc8833bf8a7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants