anmonteiro / lumo

Fast, cross-platform, standalone ClojureScript environment
Eclipse Public License 1.0
1.88k stars 85 forks source link

Improvements to exception messages and printing #474

Open metametadata opened 5 years ago

metametadata commented 5 years ago

Lumo v1.10.1.

Steps (based on https://dev.clojure.org/jira/browse/CLJS-2913?focusedCommentId=50751):

Execute in Lumo:

(require '[cljs.spec.alpha :as s])
(require '[cljs.spec.test.alpha :as st])

;; instrumenting a function
(s/fdef foobar :args (s/cat :x int?))
(defn foobar [x] x)

(st/instrument)

;; set up an example spec printer
(set! s/*explain-out* (fn [e-data] (println "SPEC ERROR!")))

(foobar "")

Actual:

Call to #'cljs.user/foobar did not conform to spec.

Expected:

Execution error - invalid arguments to user/foobar at (REPL:1).
SPEC ERROR!

See the related Planck issue https://github.com/planck-repl/planck/issues/845 which in turn follows https://dev.clojure.org/jira/browse/CLJS-2913.

Also this https://github.com/bhb/expound issue seems to be related (as the lib is based on setting s/*explain-out*): https://github.com/bhb/expound/issues/152.

metametadata commented 5 years ago

I tried to find some temporary workaround. But so far the only thing I came up with is redefining printing of ExceptionInfo:

(require '[clojure.spec.alpha :as s]
         '[cljs.spec.test.alpha :as st]
         '[cljs.repl :as repl])

(extend-type ExceptionInfo
  IPrintWithWriter

  (-pr-writer
    [o writer _opts]
    (-write writer (repl/error->str o))))

And then after spec fails one can evaluate *e to get the full pretty-printed error:

(s/fdef foobar :args (s/cat :x int?))
(defn foobar [x] x)
(st/instrument)
cljs.user=> (foobar "")
Call to #'cljs.user/foobar did not conform to spec.
     (new)
     Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (NO_SOURCE_FILE <embedded>:2053:72)
     ....

cljs.user=> *e
Execution error - invalid arguments to cljs.user/foobar at (<cljs repl>:1).
"" - failed: int? at: [:x]

This will not help in case the script is executed from file.

metametadata commented 5 years ago

A better workaround is to patch lumo.repl/handle-error:

; test.cljs
(ns my.test
  (:require [clojure.spec.alpha :as s]
            [cljs.spec.test.alpha :as st]
            [cljs.repl :as repl]
            [lumo.repl :as lumo-repl]))

; HACK: workaround for https://github.com/anmonteiro/lumo/issues/474
(set! lumo-repl/handle-error
      (fn custom-handle-error
        [error stacktrace?]
        (#'lumo-repl/print-error error stacktrace?)

        (print (repl/error->str error))

        (if-not (:repl? @#'lumo-repl/app-opts)
          (set! (. js/process lumo-repl/-exitCode) 1)
          (set! *e (#'lumo-repl/extract-cljs-js-error error)))))

(s/fdef foobar :args (s/cat :x int?))
(defn foobar [x] x)
(st/instrument)

(foobar "")

lumo test.cljs will print:

Call to #'my.test/foobar did not conform to spec.
     (new)
     Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (NO_SOURCE_FILE <embedded>:2053:72)
     Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$2 (NO_SOURCE_FILE <embedded>:2052:449)
     (/Users/yuri/dev/_ds/dev/test.cljs:132:25)
     (/Users/yuri/dev/_ds/dev/test.cljs:162:8)
     G__3721__delegate (/Users/yuri/dev/_ds/dev/test.cljs:172:5)
     G__3721 (/Users/yuri/dev/_ds/dev/test.cljs:192:26)
     Object.<anonymous> (/Users/yuri/dev/_ds/dev/test.cljs:46:16)
     Module._compile (internal/modules/cjs/loader.cljs:805:30)
     (Object.It)

Execution error - invalid arguments to my.test/foobar at (<cljs repl>:1).
"" - failed: int? at: [:x]
vincent-dm commented 5 years ago

@anmonteiro My colleague @metametadata provided his info/insight here, but I'm not sure what you mean with the help wanted tag. Do you mean a pull request or more info about the problem? Or something else?

anmonteiro commented 5 years ago

@vincent-dm I don't know what the problem is, and don't have too much time to investigate. The help wanted label means I'm welcome to a PR if someone wants to produce it.