Git Product home page Git Product logo

expound's People

Contributors

arichiardi avatar avocade avatar benalbrecht avatar bhb avatar dependabot[bot] avatar eerohele avatar eneroth avatar kelvinqian00 avatar martinklepsch avatar mpenet avatar vemv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

expound's Issues

ArityException when calling expound on a multi-spec with custom retag function

Take this example code:

(ns dev.expound
  (:require
    [clojure.spec.alpha :as s]
    [clojure.spec.gen.alpha :as gen]
    [expound.alpha :as expound]))

(defmulti bar-spec :type)

(s/def ::b string?)

(defmethod bar-spec ::b
  [_]
  (s/keys :req [::b]))

(s/def ::bar (s/multi-spec bar-spec (fn [val tag]
                                      (assoc val :type tag))))

I realize in this trivial example the retag function should be :type but for the sake of producing the error in more complex cases, I made it a function.

Running (expound/expound ::bar {}) produces this exception:

clojure.lang.ArityException: Wrong number of args (1) passed to: expound/fn--1994
	at clojure.lang.AFn.throwArity(AFn.java:429)
	at clojure.lang.AFn.invoke(AFn.java:32)
	at expound.alpha$no_method.invokeStatic(alpha.cljc:255)
	at expound.alpha$no_method.invoke(alpha.cljc:245)
	at expound.alpha$eval1720$fn__1721$fn__1722.invoke(alpha.cljc:396)
	at clojure.core$map$fn__5587.invoke(core.clj:2745)
	at clojure.lang.LazySeq.sval(LazySeq.java:40)
	at clojure.lang.LazySeq.seq(LazySeq.java:49)
	at clojure.lang.LazySeq.first(LazySeq.java:71)
	at clojure.lang.RT.first(RT.java:685)
	at clojure.core$first__5106.invokeStatic(core.clj:55)
	at clojure.string$join.invokeStatic(string.clj:180)
	at clojure.string$join.invoke(string.clj:180)
	at expound.alpha$eval1720$fn__1721.invoke(alpha.cljc:397)
	at clojure.lang.MultiFn.invoke(MultiFn.java:260)
	at expound.alpha$eval1730$fn__1731.invoke(alpha.cljc:411)
	at clojure.lang.MultiFn.invoke(MultiFn.java:260)
	at expound.alpha$print_explain_data$iter__1855__1859$fn__1860$fn__1861.invoke(alpha.cljc:704)
	at expound.alpha$print_explain_data$iter__1855__1859$fn__1860.invoke(alpha.cljc:702)
	at clojure.lang.LazySeq.sval(LazySeq.java:40)
	at clojure.lang.LazySeq.seq(LazySeq.java:49)
	at clojure.lang.RT.seq(RT.java:528)
	at clojure.core$seq__5124.invokeStatic(core.clj:137)
	at clojure.core$apply.invokeStatic(core.clj:652)
	at clojure.core$apply.invoke(core.clj:652)
	at expound.alpha$print_explain_data.invokeStatic(alpha.cljc:701)
	at expound.alpha$print_explain_data.invoke(alpha.cljc:687)
	at expound.alpha$printer_str.invokeStatic(alpha.cljc:842)
	at expound.alpha$printer_str.invoke(alpha.cljc:824)
	at expound.alpha$expound_str.invokeStatic(alpha.cljc:904)
	at expound.alpha$expound_str.invoke(alpha.cljc:896)
	at expound.alpha$expound.invokeStatic(alpha.cljc:917)
	at expound.alpha$expound.invoke(alpha.cljc:914)
	at dev.expound$eval2002.invokeStatic(form-init5270577758905363292.clj:1)
	at dev.expound$eval2002.invoke(form-init5270577758905363292.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:7062)
	at clojure.lang.Compiler.eval(Compiler.java:7025)
	at clojure.core$eval.invokeStatic(core.clj:3206)
	at clojure.core$eval.invoke(core.clj:3202)
	at clojure.main$repl$read_eval_print__8572$fn__8575.invoke(main.clj:243)
	at clojure.main$repl$read_eval_print__8572.invoke(main.clj:243)
	at clojure.main$repl$fn__8581.invoke(main.clj:261)
	at clojure.main$repl.invokeStatic(main.clj:261)
	at clojure.main$repl.doInvoke(main.clj:177)
	at clojure.lang.RestFn.invoke(RestFn.java:1523)
	at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__818.invoke(interruptible_eval.clj:87)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.core$apply.invokeStatic(core.clj:657)
	at clojure.core$with_bindings_STAR_.invokeStatic(core.clj:1965)
	at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1965)
	at clojure.lang.RestFn.invoke(RestFn.java:425)
	at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invokeStatic(interruptible_eval.clj:85)
	at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:55)
	at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__863$fn__866.invoke(interruptible_eval.clj:222)
	at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__858.invoke(interruptible_eval.clj:190)
	at clojure.lang.AFn.run(AFn.java:22)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

Add Ansi coloring printer

Awesome awesome project!

For outputing to terminal, say for instrument called within clojure.test, it would be awesome to have ansi color codes.

Just an idea, keep up the good work and thanks!

consider shorting down error message on sequence failure

For one of my api endpoints I have a quite long response which is compressed of several so-called steps. Each step is an object on its own.

The problem arises when one of the last item of the validation fails. It seems that expound simply replaces each object in the sequence with ... which is fine for short sequences but for longer ones becomes a problem (See output below)

-- Spec failed --------------------

  {:code ...,
   :uuid ...,
   :waypoints ...,
   :route
   {:distance ...,
    :duration ...,
    :steps
    (...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     ...
     {:mode "transit",
            ^^^^^^^^^
      :maneuver ...,
      :distance ...,
      :duration ...,
      :geometry ...,
      :name ...}
     ...
     ...)}}

should be: "walking"

-- Relevant specs -------

:walk/mode:
  #{"walking"}
:walk/step:
  (clojure.spec.alpha/merge
   (clojure.spec.alpha/keys :req-un [:walk/mode :walk/maneuver])
   :step/base)
:hiposfer.kamal.specs.directions/step:
  (clojure.spec.alpha/or :walk :walk/step :transit :transit/step)
:hiposfer.kamal.specs.directions/steps:
  (clojure.spec.alpha/coll-of
   :hiposfer.kamal.specs.directions/step
   :kind
   clojure.core/sequential?)
:hiposfer.kamal.specs.directions/route:
  (clojure.spec.alpha/keys
   :req-un
   [:hiposfer.kamal.specs.directions/distance
    :hiposfer.kamal.specs.directions/duration
    :hiposfer.kamal.specs.directions/steps])
:hiposfer.kamal.specs.directions/response:
  (clojure.spec.alpha/keys
   :req-un
   [:hiposfer.kamal.specs.directions/code]
   :opt-un
   [:hiposfer.kamal.specs.directions/waypoints
    :hiposfer.kamal.specs.directions/route])

Npm packaging

Hey @bhb other crazy idea ๐Ÿ˜„

I attach a blog post how to do it but of course I can help.

This would allow seemless integration with lumo.

How does it sound?

Errors with large data structures became harder to read

I use expound in edna and I noticed that errors in 0.7.1 were harder to read than in 0.7.0 when they occur inside a large outer data structure. In 0.7.0, it points to the specific part of the data structure first:

Exception in thread "main" java.lang.Exception: -- Syntax error -------------------

  [...
   [:guitarx
    ^^^^^^^^
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...]
<snip>

In 0.7.1, it prints the entire data structure first, and you have to scroll (sometimes far) down to see it eventually point to the specific part of the data structure where the error is:

Exception in thread "main" java.lang.Exception: -- Spec failed --------------------

  [{:tempo 80}
   [:guitarx {:octave 3} 1/16 :b :+c 1/8 :+d :b :+c :a :b :g :a]
   [:banjo {:octave 3} 1/16 :b :+c 1/8 :+d :b :+c :a :b :g :a]
   [:guitar {:octave 3} 1/16 :b :+c 1/8 :+d :b :+c :a :b :g :a]
   [:guitar {:octave 3} 1/2 :d 1/8 :g :g :a :b :g :b 1/2 :a]
   [:banjo {:octave 3} 1/8 :g :g :a :b 1/2 :g]
   [:guitar {:octave 2} 1/16 :g :g 1/8 :g :a :b :+c :+d :+c 1/2 :b]
   [:banjo {:octave 3} 1/16 :g :g 1/8 :g :a :b :+c :+d :+c 1/2 :b]
   [:guitar {:octave 2} 1/16 :g :g 1/8 :g :a :b :+c :+d :+c 1/2 :b]
   [:banjo {:octave 3} 1/16 :g :g 1/8 :g :a :b :+c :+d :+c 1/2 :b]
   [:guitar {:octave 3} 1/16 :g :g 1/8 :g :a :b :+c :+d :+c 1/2 :b]
   [:banjo {:octave 3} 1/16 :g :g 1/8 :g :a :b :+c :+d :+c 1/2 :b]
   [:guitar
    {:octave 4}
    1/16
    #{:-g :-b :d}
    #{:-g :-b :d}
<snip>
-- Spec failed --------------------

  [...
   [:guitarx {:octave 3} 1/16 :b :+c 1/8 :+d :b :+c :a :b :g :a]
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   ...
   ...
   ...
   ...
   ...
   ...
   ...
   ...
<snip>
-- Syntax error -------------------

  [...
   [:guitarx
    ^^^^^^^^
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...
    ...]
<snip>

I posted a code example and the output of both versions here https://gist.github.com/oakes/dbc902e8fb077d6430fa0909cf4d7272

error in clojurescript

Hi,
I'm beginning to use spec with clojurescript.
But I can't use this library.
s/explain works but not expound

cljs.user=> (expound/expound :example/place {})

#object[TypeError TypeError: Cannot read property 'cljs$lang$applyTo' of undefined]
TypeError: Cannot read property 'cljs$lang$applyTo' of undefined

NullPointerException when spec uses conformer

The following works with Clojure.spec explain but not on expound:

(s/def ::radius (s/or :unlimited #(= "unlimited" %) :distance (s/and number? #(> % 0))))
(s/def ::radiuses (s/coll-of ::radius))

(s/def ::radiuses-raw
  (s/and string? #(re-matches rads-regex %)
         (s/conformer parse-radiuses)
         ::radiuses))

;; works
(s/explain ::radiuses-raw "1200.50;100;500;unlimited;100")
;; crashes
(expound/expound ::radiuses-raw "1200.50;100;500;unlimited;100")

clojure "1.9.0-alpha17"
expound "0.1.1"

Here is the stacktrace that I obtained using aviso/pretty (let me know if you need the full raw one)

clojure.core/eval    core.clj: 3194
                              ...                  
                    user/eval3488   REPL Input     
                              ...                  
    service.routing.spec/eval3492    spec.clj:   62
            expound.alpha/expound  alpha.cljc:  541
        expound.alpha/expound-str  alpha.cljc:  527
              clojure.string/join  string.clj:  180
               clojure.core/first    core.clj:   55
                              ...                  
expound.alpha/expound-str/iter/fn  alpha.cljc:  528
                              ...                  
        expound.alpha/eval3273/fn  alpha.cljc:  404
   expound.alpha/value-in-context  alpha.cljc:  201
   expound.alpha/highlighted-form  alpha.cljc:  188
           clojure.string/replace  string.clj:  101
         java.lang.NullPointerException: 
clojure.lang.Compiler$CompilerException: java.lang.NullPointerException, compiling:(/home/carocad/Proyectos/service.routing/src/service/routing/spec.clj:62:1)

Alternation for missing element doesn't display correctly

Repro:

(require '[expound.alpha :as expound])
(require '[clojure.spec.alpha :as s])
(set! s/*explain-out* expound/printer)
(defn hello "hello world")

Actual:

-- Syntax error -------------------

  (hello "hello world")

should have additional elements. The next element is named `:args` and satisfies

  (clojure.spec.alpha/alt
   :arity-1
   :clojure.core.specs.alpha/args+body
   :arity-n
   (clojure.spec.alpha/cat
    :bodies
    (clojure.spec.alpha/+
     (clojure.spec.alpha/spec :clojure.core.specs.alpha/args+body))
    :attr
(clojure.spec.alpha/? map?)))

Expected:

The inner alt should be displayed as a series of or clauses

"Cannot convert path" when a failed spec contains `s/keys*`

Quick example:

(ns user.test
  (:require [clojure.spec.alpha :as s] 
            [expound.alpha :as expound]))

(set! s/*explain-out* expound/printer)

(s/def ::a #{1})
(s/def ::b #{2})

(s/explain (s/keys* :opt-un [::a ::b]) [:a "foo"])
;; =>
;; ExceptionInfo Cannot convert path. This can be caused by using conformers to transform values, which is not supported in Expound  clojure.core/ex-info

As far as I understand, this is similar to #102 and would be resolved (kind of) by #78, but since there are no issues mentioning s/keys* specifically I decided to create this issue anyway in case someone else runs into this.

By the way, thanks for creating this library, it's a must-have!

Printing messages without newlines or separators

Hi!

I'm trying to use expound for generating nice ex-info objects.

Example:

(throw (ex-info "Validation failed" {:explanation (with-out-str (println (apply expound/expound args)))}))

The problem is, the \ns and --------------------s don't make sense in this context, they make things less readable:

image

Is there currently an option to remove them?

Thanks - Victor

For simple predicates, expound reports "unknown" spec

(expound/expound string? 1)

Actual:

-- Spec failed --------------------

  1

should satisfy

  unknown

Expected:

-- Spec failed --------------------

  1

should satisfy

  string?

We are looking just for the predicate, which is unknown in this case. We should look at the :clojure.spec.alpha/spec key (top-level)

Adding examples to error messages

@bhb

The other day we talked about your ideas to add "did you mean..." examples to an error message by filling in the missing arguments based on the spec. I still think that's a great idea. Here is another cool approach that @oakes laid out in a gist: https://gist.github.com/oakes/8db57ac808bf6ec144d627fd83a89da3

It uses defexamples to show show an example of how a function can be used. (I appreciate his comment about how examples are especially helpful for non-English speakers).

Maybe if a defexample is defined for a function, you could show that after an expounded error message.

Better yet - show everything:

  1. Show expound error message
  2. Show their function with the corrected arguments. If you don't have enough information to reliable give them an example, don't show it. This could be collapsed by default in an IDE
  3. Show the defexample if it's available. This could also be collapsed by default in an IDE

If the expound error message wasn't enough for me to figure out my problem, I would love to have multiple examples right there, in context, for me to figure it out. It would be nice to not be overwhelmed with information so it would be nice to optionally expand them with keybindings (or clicking in an IDE UI).

You could build this support directly into expound. Another direction could be that expound turns into a type of platform, where a user could install plugins such as defexemple or other things into it.

What do you think?

This ticket may be too broad - feel free to close it in favor of more specific tickets.

Limitation on using conformed values limits usefulness of some `s/and` specs

Expound doesn't support using conformers to coerce values, because it significantly complicates the way Expound highlights the bad value (Expound uses a bunch of heurisitics to try to disambiguate the information returned by explain-data and these heuristics rely on the original unconformed value appearing the larger structure).

However, this restriction means that Expound can't print error messages for some and specs, since and conforms the values.

user=> (require '[clojure.spec.alpha :as s])
nil
user=> (require '[expound.alpha :as expound])
nil
user=> (s/def ::sorted-pair (s/and (s/cat :x int? :y int?) #(< (-> % :x) (-> % :y))))
:user/sorted-pair
user=> (s/explain ::sorted-pair [1 0])
nil
val: {:x 1, :y 0} fails spec: :user/sorted-pair predicate: (< (-> % :x) (-> % :y))
user=> (expound/expound ::sorted-pair [1 0])
ExceptionInfo Cannot convert path. This can be caused by using conformers to transform values, which is not supported in Expound  clojure.core/ex-info (core.clj:4739)

Last line of output should end in newline

Used from the terminal:

boot.user=> (expound/expound :example/place {})
-- Spec failed --------------------

  {}

should contain keys: `:city`,`:state`

-- Relevant specs -------

:example/place:
  (clojure.spec.alpha/keys
   :req-un
   [:example.place/city :example.place/state])

-------------------------
Detected 1 errornil

The output (nil) is glued to the text. I think the last line printed by expound should end with a newline (like s/explain).

(To reproduce I use BOOT_VERSION=2.7.2-SNAPSHOT BOOT_CLOJURE_VERSION=1.9.0-alpha17 rlwrap boot -d expound bare-repl)

s/coll-of on sets fails

=> (ex/expound (s/coll-of integer?) #{:a})
java.lang.UnsupportedOperationException: nth not supported on this type: PersistentHashSet

As far as I know, s/coll-of should be applicable to non-sequantial collections (including sets).
According to the stack trace, it looks like the error occurs here:

(recur (nth form k ::not-found) rst (conj in' k)))))

Spec error refers to `:args` incorrectly

=> (let [a] 2)
CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec:
-- Syntax error -------------------

  ([a] ...)
   ^^^

should have additional elements. The next element ":args" should satisfy

  any?

-- Relevant specs -------

:clojure.core.specs.alpha/bindings:
  (clojure.spec.alpha/and
   clojure.core/vector?
   (clojure.spec.alpha/* :clojure.core.specs.alpha/binding))

-------------------------

Fails to report spec error when a non-fn IFn value doesn't conform to a fspec

Repro:

=> (ex/expound (s/fspec :args (s/cat :x int?) :ret int?) :inc)

clojure.lang.ExceptionInfo: Cannot convert path. This can be caused by using conformers to transform values, which is not supported in Expound
=> (ex/expound (s/fspec :args (s/cat :x int?) :ret int?) 'inc)

clojure.lang.ExceptionInfo: Cannot convert path. This can be caused by using conformers to transform values, which is not supported in Expound
=> (ex/expound (s/fspec :args (s/cat :x int?) :ret int?) #'str)

clojure.lang.ExceptionInfo: Cannot convert path. This can be caused by using conformers to transform values, which is not supported in Expound

Expected Expound would report the spec error that the input value didn't conform to the fspec, but throws a misleading error that says there may be a conformer (which is not true, in fact).

Nested map

I have a case that's working with spec, but failing with expound:

(require '[clojure.spec.alpha :as s]
         '[expound.alpha :as e])

(s/def :db/valueType #{:db.type/ref})
(s/def :db/cardinality #{:db.cardinality/one :db.cardinality/many})
(s/def :db/unique #{:db.unique/identity})
(s/def ::attribute-schema (s/keys :opt [:db/valueType :db/cardinality :db/unique]))
(s/def ::schema (s/map-of keyword? ::attribute-schema))

(s/explain-str ::schema {:some/value {:db/unique :db.unique/value}})
;;In: [:some/value 1 :db/unique] val: :db.unique/value fails spec: :db/unique at: [1 :db/unique] ;;predicate: #{:db.unique/identity}
;;:clojure.spec.alpha/spec  :user/schema
;;:clojure.spec.alpha/value  #:some{:value #:db{:unique :db.unique/value}}

(e/expound-str ::schema {:some/value {:db/unique :db.unique/value}})
;;AssertionError Assert failed: clojure.lang.LazySeq@8de948aa
;;(every? :expound/in leaf-problems)  expound.alpha/printer-str (alpha.cljc:541)

Clojure 1.9.0-alpha19

Clojure.core macro specs

Is there a way to see the spec error generated when I type, say, (let (a 1) a) in the REPL printed by expound?

expound seems to print explain a problem twice whenever a compile time error is found

with the following setup in v0.5.1-snaptshot

(st/instrument)
(set! s/*explain-out* (expound/custom-printer {:theme :figwheel-theme}))

(let [1 2]
  3)
;; error printed twice with different exception types
;; - clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec:
;; - clojure.lang.Compiler$CompilerException: clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec:

Given that Clojure specs are quite complex the error message is equally large. Having it twice definitely doesnt help.

However the output from Expound is very organized so the problem becomes very manageable.

Hope it helps

Report on misspelled keys on `s/keys` & `s/merge`

Hi.

And thanks for the awesome lib! Would it be possible to have a way to report on extra keys on s/keys or s/merge specs? I have a configuration with mostly all the keys unqualified and optional. There is no guard against misspelled keys at the moment.

Foremost, this would be useful on the development phase, thus looking at expound :)

Added helpers on spec-tools to extract all the keys from both s/keys and s/merge that could be used/copied to get the actual set of defined keys to be checked against.

And my use-case is here.

Integrate with clojure.test.check.clojure-test/defspec

Hi,

Just a feature idea. The output of clojure.test.check.clojure-test/defspec is a bit messy, maybe expound can do something about it ? Not sure it can/should, since the output shows you the first inputs that failed, then shrink them to minimal output that fails, so it's not directly related to a misused spec. But since expound humanize spec-related error messages, I thought maybe it could do for defspec too.

The expound/def macro does not work in ClojureScript

Hi Ben!

I was trying a simple definition and I keep getting:

------ WARNING #1 --------------------------------------------------------------
 File: ...:38:1
--------------------------------------------------------------------------------
  35 |   [x]
  36 |   (= :http/malformed x))
  37 | 
  38 | (expound/def :my-namespace/js-error #(instance? js/Error %) "should be a JavaScript error instance")
-------^------------------------------------------------------------------------
 No such namespace: clojure.spec.alpha, could not locate clojure/spec/alpha.cljs, clojure/spec/alpha.cljc, or JavaScript source providing "clojure.spec.alpha"
--------------------------------------------------------------------------------
  39 | 
...
--------------------------------------------------------------------------------

------ WARNING #2 --------------------------------------------------------------
 File: .../http.cljs:38:1
--------------------------------------------------------------------------------
  35 |   [x]
  36 |   (= :http/malformed x))
  37 | 
  38 | (expound/def :my-namespace/js-error #(instance? js/Error %) "should be a JavaScript error instance")
-------^------------------------------------------------------------------------
 Use of undeclared Var clojure.spec.alpha/def-impl
--------------------------------------------------------------------------------
  39 | 
...
--------------------------------------------------------------------------------

It seems that the expound/def macro cannot expand to s/def because in cljs the alias does not actually expand correctly - maybe renaming from clojure.spec.alpha to cljs.spec.alpha is not done?

I do not know if true but that is what I gather from the errors above.

consider making the `relevant specs` section optional

As specs grow the failing part might be quite deep in the validation stack.

This creates some readability problems since the relevant-specs section becomes too large to be usable at all. See example below:

screen shot 2018-04-03 at 10 53 50

I have a 21 inch screen (I think :D ) and even so I am not able to display the complete error without having to scroll around trying to find the errors.

I propose two options that might help solve this:

  • make relevant specs section optional and configurable when setting up the printer
  • collapse irrelevant spec pieces into ... and show only the key-predicate that failed

I think that expound already goes to great lengths to manage option 2 so I guess that would only leave option 1 ๐Ÿ˜ž ?

Hope it helps

Error message for failing `fspec` spec is not useful

(require '[clojure.spec.alpha :as s])
(require '[expound.alpha :as expound])

(s/def ::my-fn (s/fspec
                :args (s/cat :x int? :y int?)))

(defn foobar [x y]
  (/ x y))

(s/explain ::my-fn foobar)
;; val: (0 0) fails spec: :user/my-fn predicate: (apply fn),  Divide by zero
;; :clojure.spec.alpha/spec  :user/my-fn
;; :clojure.spec.alpha/value  #function[user/foobar]


(expound/expound ::my-fn foobar)
;; -- Spec failed --------------------

;;   #function[user/foobar]

;; should satisfy

;;   (apply fn)

;; -- Relevant specs -------

;; :user/my-fn:
;;   (clojure.spec.alpha/fspec
;;    :args
;;    (clojure.spec.alpha/cat :x clojure.core/int? :y clojure.core/int?)
;;    :ret
;;    clojure.core/any?
;;    :fn
;;    nil)

;; -------------------------
;; Detected 1 error

Don't pack resources/public/index.html into the release jar

I am using expound in development mode for my app, and due to the way my app's routes are implemented, expound's index.html takes precedence over my app in dev mode.

It appears to be only useful for development of expound itself, therefore I think it should not be included in the release jars.

does not work with `s/or` and multiple spec maps

I'm running into this assertion error:

(defn key->spec [keys problems]
  (assert (apply = (map :expound/via problems)))
....

https://github.com/bhb/expound/blob/master/src/expound/printer.cljc#L47

Any idea why this may be?
I'll dig in and see what the actual values are. If anything I think the error message here could be improved since the vanilla assert message is not helpful.

Here is the full stack trace:

1. Unhandled java.lang.AssertionError
   Assert failed: (apply = (map :expound/via problems))

              printer.cljc:   47  expound.printer$key__GT_spec/invokeStatic
              printer.cljc:   46  expound.printer$key__GT_spec/invoke
              printer.cljc:  186  expound.printer$print_spec_keys$fn__21784/invoke
              printer.cljc:  186  expound.printer$print_spec_keys/invokeStatic
              printer.cljc:  177  expound.printer$print_spec_keys/invoke
                alpha.cljc:  225  expound.alpha$explain_missing_keys/invokeStatic
                alpha.cljc:  216  expound.alpha$explain_missing_keys/invoke
                alpha.cljc:  230  expound.alpha$eval21950$fn__21951/invoke
              MultiFn.java:  260  clojure.lang.MultiFn/invoke
                alpha.cljc:  242  expound.alpha$eval21954$fn__21955/invoke
              MultiFn.java:  260  clojure.lang.MultiFn/invoke
                alpha.cljc:  459  expound.alpha$problem_group_str1/invokeStatic
                alpha.cljc:  457  expound.alpha$problem_group_str1/invoke
                alpha.cljc:  504  expound.alpha$printer_str$iter__22065__22069$fn__22070/invoke
              LazySeq.java:   40  clojure.lang.LazySeq/sval
              LazySeq.java:   49  clojure.lang.LazySeq/seq
                 Cons.java:   39  clojure.lang.Cons/next
              LazySeq.java:   81  clojure.lang.LazySeq/next
                   RT.java:  703  clojure.lang.RT/next
                  core.clj:   64  clojure.core/next
                string.clj:  180  clojure.string/join
                string.clj:  180  clojure.string/join
                alpha.cljc:  503  expound.alpha$printer_str/invokeStatic
                alpha.cljc:  479  expound.alpha$printer_str/invoke
                alpha.cljc:  515  expound.alpha$custom_printer$fn__22092/invoke
                alpha.cljc:  520  expound.alpha$printer/invokeStatic
                alpha.cljc:  517  expound.alpha$printer/invoke
                 alpha.clj:  250  clojure.spec.alpha/explain-out
                 alpha.clj:  246  clojure.spec.alpha/explain-out
                  test.clj:  115  orchestra.spec.test/spec-checking-fn/conform!/fn
                  test.clj:  115  orchestra.spec.test/spec-checking-fn/conform!
                  test.clj:  125  orchestra.spec.test/spec-checking-fn/fn
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  Var.java:  702  clojure.lang.Var/applyTo
                  core.clj:  659  clojure.core/apply
                  core.clj:  652  clojure.core/apply

Add documentation

None of the functions have docstrings, and a page listing all public functions would be good.

Strange handling of complement / not

Hi again!

By evaluating (expound/expound (complement string/blank?) "") one will get:

nil
-- Spec failed --------------------

  ""

should satisfy

  /



-------------------------
Detected 1 error

The / is quite confusing.

If I try with (expound/expound (fn [x] (not (string/blank? x))) "") I'll get the same output.

Tried out with clojurescript.

Hope this one can be improved!

Cheers - Victor

alter-var-root suggestion doesn't seem to have any effect

I'm not sure if this is actually an issue with expound, or if I'm misunderstanding how it's supposed to work.

Desired behaviour

All spec errors are handled by expound's printer, no matter if they are made on the REPL during development or at any other place.

Steps I thought I needed to do

Add the following code to the namespace that contains my -main function, which is also the namespace that CIDER loads by default.

(alter-var-root #'s/*explain-out* (constantly expound/printer))

What actually happens

When I deliberately make a mistake in the REPL, e.g. (defn a 1), I don't see expound's output, only the usual clojure.spec output.

What seems to work

Doing (set! s/*explain-out* expound/printer) interactively after I start/connect to the REPL -- then syntax errors are caught and printed by expound. I'm not sure how this would work for spec errors deep inside the code in other threads.

How does it look like

$ lein repl
nREPL server started on port 62015 on host 127.0.0.1 - nrepl://127.0.0.1:62015
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.9.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_152-b16
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> (require '[expound.alpha :as expound]
  #_=>          '[clojure.spec.alpha :as s])
nil
user=> (defn a 1) ;; <------------ 1. expected, no expound integration yet

CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/defn did not conform to spec:
In: [1] val: 1 fails spec: :clojure.core.specs.alpha/arg-list at: [:args :bs :arity-1 :args] predicate: vector?
In: [1] val: 1 fails spec: :clojure.core.specs.alpha/args+body at: [:args :bs :arity-n :bodies] predicate: (cat :args :clojure.core.specs.alpha/arg-list :body (alt :prepost+body (cat :prepost map? :body (+ any?)) :body (* any?)))
 #:clojure.spec.alpha{:problems ({:path [:args :bs :arity-1 :args], :pred clojure.core/vector?, :val 1, :via [:clojure.core.specs.alpha/defn-args :clojure.core.specs.alpha/args+body :clojure.core.specs.alpha/arg-list :clojure.core.specs.alpha/arg-list], :in [1]} {:path [:args :bs :arity-n :bodies], :pred (clojure.spec.alpha/cat :args :clojure.core.specs.alpha/arg-list :body (clojure.spec.alpha/alt :prepost+body (clojure.spec.alpha/cat :prepost clojure.core/map? :body (clojure.spec.alpha/+ clojure.core/any?)) :body (clojure.spec.alpha/* clojure.core/any?))), :val 1, :via [:clojure.core.specs.alpha/defn-args :clojure.core.specs.alpha/args+body :clojure.core.specs.alpha/args+body], :in [1]}), :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x25f05c8d "clojure.spec.alpha$regex_spec_impl$reify__2436@25f05c8d"], :value (a 1), :args (a 1)}, compiling:(/private/var/folders/yw/d0ggvvcs5lz1fw09p76rl3_r0000gn/T/form-init4153292859114110702.clj:1:1)


user=> (alter-var-root #'s/*explain-out* (constantly expound/printer)) ;; <------------- 2. as suggested by the docs
#object[expound.alpha$printer 0x5a0e22ad "expound.alpha$printer@5a0e22ad"]
user=> (defn a 1)
CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/defn did not conform to spec:
In: [1] val: 1 fails spec: :clojure.core.specs.alpha/arg-list at: [:args :bs :arity-1 :args] predicate: vector?
In: [1] val: 1 fails spec: :clojure.core.specs.alpha/args+body at: [:args :bs :arity-n :bodies] predicate: (cat :args :clojure.core.specs.alpha/arg-list :body (alt :prepost+body (cat :prepost map? :body (+ any?)) :body (* any?)))
 #:clojure.spec.alpha{:problems ({:path [:args :bs :arity-1 :args], :pred clojure.core/vector?, :val 1, :via [:clojure.core.specs.alpha/defn-args :clojure.core.specs.alpha/args+body :clojure.core.specs.alpha/arg-list :clojure.core.specs.alpha/arg-list], :in [1]} {:path [:args :bs :arity-n :bodies], :pred (clojure.spec.alpha/cat :args :clojure.core.specs.alpha/arg-list :body (clojure.spec.alpha/alt :prepost+body (clojure.spec.alpha/cat :prepost clojure.core/map? :body (clojure.spec.alpha/+ clojure.core/any?)) :body (clojure.spec.alpha/* clojure.core/any?))), :val 1, :via [:clojure.core.specs.alpha/defn-args :clojure.core.specs.alpha/args+body :clojure.core.specs.alpha/args+body], :in [1]}), :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x25f05c8d "clojure.spec.alpha$regex_spec_impl$reify__2436@25f05c8d"], :value (a 1), :args (a 1)}, compiling:(/private/var/folders/yw/d0ggvvcs5lz1fw09p76rl3_r0000gn/T/form-init4153292859114110702.clj:1:1)



user=> (set! s/*explain-out* expound/printer) ;; <------------ 3. this seems to work
#object[expound.alpha$printer 0x5a0e22ad "expound.alpha$printer@5a0e22ad"]
user=> (defn a 1)

CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/defn did not conform to spec:
-- Spec failed --------------------

  (... 1)
       ^

should satisfy

  vector?

or

  (clojure.spec.alpha/cat
   :args
   :clojure.core.specs.alpha/arg-list
   :body
   (clojure.spec.alpha/alt
    :prepost+body
    (clojure.spec.alpha/cat
     :prepost
     map?
     :body
     (clojure.spec.alpha/+ any?))
    :body
    (clojure.spec.alpha/* any?)))

-- Relevant specs -------

:clojure.core.specs.alpha/arg-list:
  (clojure.spec.alpha/and
   clojure.core/vector?
   (clojure.spec.alpha/cat
    :args
    (clojure.spec.alpha/* :clojure.core.specs.alpha/binding-form)
    :varargs
    (clojure.spec.alpha/?
     (clojure.spec.alpha/cat
      :amp
      #{'&}
      :form
      :clojure.core.specs.alpha/binding-form))))
:clojure.core.specs.alpha/args+body:
  (clojure.spec.alpha/cat
   :args
   :clojure.core.specs.alpha/arg-list
   :body
   (clojure.spec.alpha/alt
    :prepost+body
    (clojure.spec.alpha/cat
     :prepost
     clojure.core/map?
     :body
     (clojure.spec.alpha/+ clojure.core/any?))
    :body
    (clojure.spec.alpha/* clojure.core/any?)))
:clojure.core.specs.alpha/defn-args:
  (clojure.spec.alpha/cat
   :name
   clojure.core/simple-symbol?
   :docstring
   (clojure.spec.alpha/? clojure.core/string?)
   :meta
   (clojure.spec.alpha/? clojure.core/map?)
   :bs
   (clojure.spec.alpha/alt
    :arity-1
    :clojure.core.specs.alpha/args+body
    :arity-n
    (clojure.spec.alpha/cat
     :bodies
     (clojure.spec.alpha/+
      (clojure.spec.alpha/spec :clojure.core.specs.alpha/args+body))
     :attr
     (clojure.spec.alpha/? clojure.core/map?))))

-------------------------
Detected 1 error
 #:clojure.spec.alpha{:problems ({:path [:args :bs :arity-1 :args], :pred clojure.core/vector?, :val 1, :via [:clojure.core.specs.alpha/defn-args :clojure.core.specs.alpha/args+body :clojure.core.specs.alpha/arg-list :clojure.core.specs.alpha/arg-list], :in [1]} {:path [:args :bs :arity-n :bodies], :pred (clojure.spec.alpha/cat :args :clojure.core.specs.alpha/arg-list :body (clojure.spec.alpha/alt :prepost+body (clojure.spec.alpha/cat :prepost clojure.core/map? :body (clojure.spec.alpha/+ clojure.core/any?)) :body (clojure.spec.alpha/* clojure.core/any?))), :val 1, :via [:clojure.core.specs.alpha/defn-args :clojure.core.specs.alpha/args+body :clojure.core.specs.alpha/args+body], :in [1]}), :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x25f05c8d "clojure.spec.alpha$regex_spec_impl$reify__2436@25f05c8d"], :value (a 1), :args (a 1)}, compiling:(/private/var/folders/yw/d0ggvvcs5lz1fw09p76rl3_r0000gn/T/form-init4153292859114110702.clj:1:1)
user=>

Project.clj

(defproject exp-bug "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.9.0"]
                 [expound "0.7.1"]])

Custom error messages for preds look weird

(s/def ::resolve (s/or :function ::resolver-fn
                       :protocol ::resolver-type))
(s/def ::resolver-fn fn?)
(expound/def ::resolver-type #(satisfies? resolve/FieldResolver %) "implement the com.walmartlabs.lacina.resolve/FieldResolver protocol")

(s/explain ::schema/resolve {})
-- Spec failed --------------------

  {}

should satisfy

  fn?

or

implement the com.walmartlabs.lacina.resolve/FieldResolver protocol

Note that last line looks like it is not indented correctly.

In some cases, we want custom error message to be all the way to the left though (this is current behavior):

(s/def :example/temp #{:hot :cold})  
(expound/expound :example/temp 1)
;;-- Spec failed --------------------
;;
;;  1
;;
;;should be one of: :cold, :hot

(expound/def :example/name string? "should be a string")
(expound/expound :example/name 1)
;;-- Spec failed --------------------
;;
;;  1
;;
;;should be a string

For function specs, show which spec failed.

When instrumenting, especially with orchestra, expound provides less information than clojure.spec would, since it doesn't say whether or not it was the :ret or :args or :fn that failed to validate.

Are you open to adding this support?

Support for `spec/assert`?

Thanks for expound, it's a great addition to spec.

I've been using clojure.spec/assert in combination with Clojure's pre-conditions. Would you be interested in a PR which adds support for assertions, or is that out-of-scope for expound?

Cannot report error when `multi-spec` is combined with another spec via `and`

(defmulti fruit :fruit/type)
(defmethod fruit :orange [_]
  (s/keys))
(defmethod fruit :apple [_]
  (s/keys))


(s/def ::fruit1 (s/multi-spec fruit :fruit/type))
(expound/expound ::fruit1 {}) ;; works

(s/def ::fruit2 (s/and
                 map?
                 (s/multi-spec fruit :fruit/type)))
(expound/expound ::fruit2 {:fruit/type :orange}) ;; works
(expound/expound ::fruit2 {:fruit/type :banana}) ;; error

Emacs cider

Hello,

I would like to use in Emacs + cider with that project setup:

(defproject nativeapi "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]  ;w/1.9.0 too
                 [org.clojure/spec.alpha "0.2.168"]
                 [clj-http "3.9.1"]
                 [expound "0.7.1"]
                 [org.clojure/test.check "0.9.0"]])
(ns nativeapi.core
  (:require [clj-http.client :as client]
            [clojure.spec.alpha :as s]
            [clojure.test.check.generators :as gen]
            [expound.alpha :as expound]
            ))

and I got this message:

CompilerException java.lang.Exception: namespace 'expound.paths' not found, compiling:(expound/problems.cljc:1:1)

Emacs 25.3, Cider version 20180805.1016

p.s. in Repl no problem

Expound omits second problem

Compare:

(s/explain
   (:args (s/get-spec `defn))
   `(~'foo (~'arg1 ~'arg2) ~'arg3))

Output is:

In: [1 0] val: arg1 fails spec: :clojure.core.specs.alpha/arg-list at: [:bs :arity-n :bodies :args] predicate: vector?
In: [1] val: (arg1 arg2) fails spec: :clojure.core.specs.alpha/arg-list at: [:bs :arity-1 :args] predicate: vector?

With expound:

(expound/expound
 (:args (s/get-spec `defn))
 `(~'foo (~'arg1 ~'arg2) ~'arg3))

Output (in part)

-- Spec failed --------------------

  (... (arg1 ...) ...)
        ^^^^

should satisfy

  vector?

Note that the more interesting case is omitted - that the parent collection is a list instead of a vector.

Only return error message string?

Is there a way to pass a fn to spec and value and that it would return error message string.

(def email-regex #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$")

(expound/def :example/email (s/and string? #(re-matches email-regex %)) "should be a valid email address")

(expound/expound-error :example/email "sally@")

;; => "should be a valid email address"

Expound providing clojurescript?

Something in the expound's configuration causes Cursive to have trouble resolving functions cleanly. I'm not sure why this happens.

image

Tuple with set predicate not reported correctly

Hi again ๐Ÿ˜„ I have a bit of an improvement request ๐Ÿ˜„

I have a spec with a set predicate:

(s/def :stm/success-state (s/tuple #{:start :end :latest-event :attempt-commit}
                                   any?
                                   nil?))

Spec error was:

Error: Spec assertion failed
In: [0] val: :error fails at: [0] predicate: #{:start :end :latest-event :attempt-commit}
In: [2] val: #object[Error Error: Oh noes!] fails at: [2] predicate: nil?
:cljs.spec.alpha/spec  :stm/success-state
:cljs.spec.alpha/value  [:error nil #object[Error Error: Oh noes!]]
:cljs.spec.alpha/failure  :assertion-failed

And expound error:

Error: Call to #'expound.alpha/value-in-context did not conform to spec:
<filename missing>:<line number missing>
-- Spec failed --------------------

Function arguments

  (... 0 ... ... ...)
       ^

should be one of: `:args`,`:fn`,`:ret`



-- Spec failed --------------------

Function arguments

  (... 0 ... ... ...)
       ^

should satisfy

  nil?



-------------------------


Expound cannot handle js/NaN

Hi!

I found the following issue, where spec can handle NaN but Expound not:

(spec/conform (constantly false) js/NaN) -> :cljs.spec.alpha/invalid


(expound/expound (constantly false) js/NaN):

{:message "Cannot convert path. This can be caused by using conformers to transform values, which is not supported in Expound", :data {:form NaN, :val NaN, :in [], :in' []}}

Thanks for this library, we've been enjoying it at work for quite a few months now!

Cheers - Victor

Expound gives misleading error when `ns` call is incorrect

Repro:

(st/instrument)
(set! s/*explain-out* expound/printer)
(ns foo (:refer-clojure :as [rand-int]))

Actual:

Call to clojure.core/refer-clojure did not conform to spec:
-- Spec failed --------------------

((... :as) ...)
      ^^^

should be: `:exclude`

Expected: The value could actually be :exclude or :only or :rename etc. Here is the default error message via explain.

Call to clojure.core/refer-clojure did not conform to spec:
In: [0 1] val: :as fails at: [:args :exclude :op :quoted-spec :spec] predicate: #{:exclude}
In: [0 1] val: :as fails at: [:args :only :op :quoted-spec :spec] predicate: #{:only}
In: [0 1] val: :as fails at: [:args :rename :op :quoted-spec :spec] predicate: #{:rename}
In: [0] val: (quote :as) fails at: [:args :exclude :op :spec] predicate: #{:exclude}
In: [0] val: (quote :as) fails at: [:args :only :op :spec] predicate: #{:only}
In: [0] val: (quote :as) fails at: [:args :rename :op :spec] predicate: #{:rename}

Details https://www.reddit.com/r/Clojure/comments/778tc2/is_clojure_19_improving_error_messages/dokmvma/

Instructions cause runtime error

Why do the docs suggest:

;; Or set it globally
(set! s/*explain-out* expound/printer)

?

This results in a runtime error:

Caused by: java.lang.IllegalStateException: Can't change/establish root binding of: *explain-out* with set

Currently, it is an error to attempt to set the root binding of a var using set!, i.e. var assignments are thread-local.

https://clojure.org/reference/vars#set

expound-printer

It'd be nice to be able to bind expound-str to s/*explain-out*. With that stest/instrument should present expound formatted descriptions in exceptions.

(binding [s/*explain-out* expound/expound-printer]
    (s/explain-str (s/coll-of integer?) {:A 1}))

The main difference to the current code is that *explain-out* printers take explain-data as an arg.

Allow configuration of irrelevant data truncation

The ommission of argument data, in failed calls to instrumented functions, is less helpful than clojure.spec would otherwise be. While I understand this brevity may be useful in some cases, my preference is to enjoy the formatting of expound without losing any data in translation. Are you open to making this truncation of irrelevant data configurable (say, using a dynamic var)?

Example:

Call to #'flarb did not conform to spec:
<filename missing>:<line number missing>

Function arguments

-- Spec failed --------------------

  (... {:my-app.common.request/url-path "api/do-things",
        :my-app.common.request/method :my-app.common.request/post,
        :my-app.common.request/content-type :my-app.common.request/edn,
        :my-app.common.request/headers {"Authorization" "Bearer meow"},
        :my-app.common.request/body
        {:my-app.common.transit.challenge/id 1,
         :my-app.common.transit.challenge/num-games 0,
         :my-app.common.transit.money/money 1},
        :my-app.common.request/response-spec ::spam} ... ...)
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

should satisfy

  integer?



-------------------------
Detected 1 error

As you can see, it's hard to tell what's wrong here. This is partially due to the ommitted data and partially due to expound not showing the relevant specs in this case.

Thank you!

Internal Expound assertion failed using ring.core.spec

I've written a function spec for my top-level ring handler, which is a function called app that calls reitit.ring/ring-handler. It looks like this:

(defn app
  []
  (rr/ring-handler
    ... ))

(s/fdef app :ret :ring/handler)

The :ring/handler spec is defined in ring-spec.

There's some kind of problem when I call (or s/explain the result of) this function that makes Expound throw an exception. It looks like this:

AssertionError Assert failed: Internal Expound assertion failed. Please report this bug at https://github.com/bhb/expound/issues: All values should be the same, but they are [{:path [:sync+async :fn :sync :args :request], :pred map?, :via [:ring/handler :ring.sync+async/handler :ring.sync.handler/args :ring.sync.handler/args :ring/request :ring/request], :expound/form #object[clojure.lang.AFunction$1 0x7024b79d "clojure.lang.AFunction$1@7024b79d"], :val :sync, :spec :ring/handler, :expound/path [:sync+async :fn :sync :args :request], :expound/in [], :in [:args 0], :expound/via [:ring/handler :ring.sync+async/handler :ring.sync.handler/args :ring.sync.handler/args :ring/request :ring/request]} {:path [:sync+async :fn :sync :ret], :pred map?, :via [:ring/handler :ring.sync+async/handler :ring/response], :expound/form #object[clojure.lang.AFunction$1 0x7024b79d "clojure.lang.AFunction$1@7024b79d"], :val [:async {:status 405, :body ""}], :spec :ring/handler, :expound/path [:sync+async :fn :sync :ret], :expound/in [], :in [:ret], :expound/via [:ring/handler :ring.sync+async/handler :ring/response]} {:path [:sync+async :fn :async :args :request], :pred map?, :via [:ring/handler :ring.sync+async/handler :ring.async.handler/args :ring.async.handler/args :ring/request :ring/request], :expound/form #object[clojure.lang.AFunction$1 0x7024b79d "clojure.lang.AFunction$1@7024b79d"], :val :sync, :spec :ring/handler, :expound/path [:sync+async :fn :async :args :request], :expound/in [], :in [:args 0], :expound/via [:ring/handler :ring.sync+async/handler :ring.async.handler/args :ring.async.handler/args :ring/request :ring/request]}]
(apply = (map :val problems))  expound.alpha/eval6753/fn--6754 (alpha.cljc:577)

(this is how it's formatted)

When I run without expound, I get the following output:

ExceptionInfo Call to #'hanabi.web/app did not conform to spec:
In: [:args 0] val: :sync fails spec: :ring/request at: [:ret :sync+async :fn :sync :args :request] predicate: map?
In: [:args 0] val: :sync fails spec: :ring/request at: [:ret :sync+async :fn :async :args :request] predicate: map?
In: [:ret] val: [:async {:status 405, :body ""}] fails spec: :ring/response at: [:ret :sync+async :fn :sync :ret] predicate: map?
val: {:status 405, :body ""} fails spec: :ring/response at: [:ret :sync :ret] predicate: (contains? % :headers)
val: ({:server-port 1, :server-name "", :remote-addr "", :uri "/", :scheme :http, :protocol "HTTP/1.1", :headers {}, :request-method :a} #object[clojure.spec.alpha$fspec_impl$reify__2451$fn__2454 0x49704cb9 "clojure.spec.alpha$fspec_impl$reify__2451$fn__2454@49704cb9"] #object[clojure.spec.alpha$fspec_impl$reify__2451$fn__2454 0x6859d673 "clojure.spec.alpha$fspec_impl$reify__2451$fn__2454@6859d673"]) fails spec: :ring.async/handler at: [:ret :async] predicate: (apply fn),  Assert failed: In: [0] val: {:status 405, :body ""} fails spec: :ring/response at: [:response] predicate: (contains? % :headers)

(pvalid? argspec args)
  clojure.core/ex-info (core.clj:4739)

Now I have no idea what's up with the spec or why Expound throws an exception, but clearly the raw spec formatting is preferable.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.