### Quick Start with `clj` Source: https://github.com/bhb/expound/blob/master/README.md Install `clojure/tools/clojure` via Homebrew and run Expound using `clj` with the provided dependency information. This example demonstrates a basic spec failure. ```bash > brew install clojure/tools/clojure > clojure -Sdeps '{:deps {friendly/friendly {:git/url "https://gist.github.com/bhb/2686b023d074ac052dbc21f12f324f18" :sha "d532662414376900c13bed9c920181651e1efeff"}}}' -X friendly/run user=> (require '[expound.alpha :as expound]) nil user=> (expound/expound string? 1) nil -- Spec failed -------------------- 1 should satisfy string? ------------------------- Detected 1 error user=> ``` -------------------------------- ### Install Expound Printer in REPL using set! Source: https://github.com/bhb/expound/blob/master/doc/faq.md Use `set!` to install the Expound printer for the current thread in a REPL environment. This is the recommended approach for interactive sessions. ```clojure (set! s/*explain-out* expound/printer) ``` -------------------------------- ### Lumo Installation Source: https://github.com/bhb/expound/blob/master/README.md Install Expound for use with Lumo via npm. ```bash npm install @bbrinck/expound ``` -------------------------------- ### Start Socket REPL Source: https://github.com/bhb/expound/blob/master/doc/development.md Starts a Clojure socket REPL on port 5555. Connect using an appropriate client like inf-clojure. ```bash clj -J-Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}" ``` -------------------------------- ### ClojureScript `*explain-out*` configuration Source: https://github.com/bhb/expound/blob/master/README.md Configure Expound in Clojure to use Expound during macro-expansion for ClojureScript projects. This example shows the command-line arguments for starting ClojureScript with Expound configured. ```bash clj -Srepro -Sdeps '{:deps {expound {:mvn/version "0.9.0"} org.clojure/test.check {:mvn/version "0.9.0"} org.clojure/clojurescript {:mvn/version "1.10.520"}}}' -e "(require '[expound.alpha :as expound]) (set! clojure.spec.alpha/*explain-out* expound.alpha/printer)" -m cljs.main -re node ``` -------------------------------- ### Start Clojurescript REPL (Node) Source: https://github.com/bhb/expound/blob/master/doc/development.md Initiates a Clojurescript REPL environment targeting Node.js. Requires Leiningen and specific profiles. ```bash lein with-profile +test-web,+cljs-repl repl ``` ```clojure (require 'cljs.repl.node) (cider.piggieback/cljs-repl (cljs.repl.node/repl-env)) ``` -------------------------------- ### Install Expound Printer for All Threads using alter-var-root Source: https://github.com/bhb/expound/blob/master/doc/faq.md Use `alter-var-root` to install the Expound printer for all threads in non-REPL environments or when `set!` is insufficient. This is necessary for programs that spawn additional threads, such as web servers, and is also required when running within an uberjar. ```clojure (alter-var-root #'s/*explain-out* (constantly expound/printer)) ``` -------------------------------- ### Expound Error Example with Macros Source: https://github.com/bhb/expound/blob/master/doc/compatibility.md Demonstrates Expound errors during macro-expansion when configured for ClojureScript. ```clojure (require '[clojure.core.specs.alpha]) nil (let [x]) Execution error - invalid arguments to cljs.analyzer/do-macroexpand-check at (analyzer.cljc:3772). -- Spec failed -------------------- ([x]) ^^^ should satisfy even-number-of-forms? -- Relevant specs ------- :cljs.core.specs.alpha/bindings: (clojure.spec.alpha/and clojure.core/vector? cljs.core.specs.alpha/even-number-of-forms? (clojure.spec.alpha/* :cljs.core.specs.alpha/binding)) ------------------------- Detected 1 error cljs.user=> ``` -------------------------------- ### Example of Spec Conformer Usage Source: https://github.com/bhb/expound/blob/master/doc/arch/adr-002.md Demonstrates using a conformer to verify a string against a regex spec. The NCV might not exist atomically in the context after conforming. ```clojure (s/def ::string-AB-seq (s/cat :a #{\A} :b #{\B})) (s/def ::string-AB (s/and ;; conform as sequence (seq function) (s/conformer seq) ;; re-use previous sequence spec ::string-AB-seq)) (s/conform ::string-AB "AC") ``` -------------------------------- ### Urn Syntax Error Example Source: https://github.com/bhb/expound/blob/master/doc/prior_art.md Illustrates Urn's syntax error reporting, showing underlining to pinpoint the error location and providing expected vs. found tokens. ```Urn > (] [ERROR] Expected ')', got ']' => :1:2 .. 1:2 ("] 1 │ (] │ ^... block opened with '(' 1 │ (] │ ^ ']' used here > ``` -------------------------------- ### Configuring `*explain-out*` for custom output Source: https://github.com/bhb/expound/blob/master/README.md Set `clojure.spec.alpha/*explain-out*` to `expound/printer` to use Expound for other Spec functions like `assert` and `explain`. This example demonstrates enabling asserts and using `binding` or `set!` to configure the printer. ```clojure (require '[clojure.spec.alpha :as s]) (require '[expound.alpha :as expound]) (s/def :example.place/city string?) (s/def :example.place/state string?) ;; Use `assert` (s/check-asserts true) ; enable asserts ;; Set var in the scope of 'binding' (binding [s/*explain-out* expound/printer] (s/assert :example.place/city 1)) (set! s/*explain-out* expound/printer) ;; (or alter-var-root - see doc/faq.md) (s/assert :example.place/city 1) ;; Use `instrument` (require '[clojure.spec.test.alpha :as st]) (s/fdef pr-loc :args (s/cat :city :example.place/city :state :example.place/state)) (defn pr-loc [city state] (str city ", " state)) (st/instrument `pr-loc) (pr-loc "denver" :CO) ;; You can use `explain` without converting to expound (s/explain :example.place/city 123) ``` -------------------------------- ### Urn Assertion Failure Example Source: https://github.com/bhb/expound/blob/master/doc/prior_art.md Demonstrates how Urn displays assertion failures, including the expression that failed and the values of sub-expressions. ```Urn > (import test ()) out = nil > (affirm (eq? '("foo" "bar" "") . (string/split "foo-bar" "-"))) [ERROR] :1 (compile#111{split,temp}:46): Assertion failed (eq? (quote ("foo" "bar" "")) (string/split "foo-bar" "-")) | | | ("foo" "bar") ("foo" "bar" "") ``` -------------------------------- ### Minimized Long Sequence Error Message Example Source: https://github.com/bhb/expound/blob/master/doc/arch/adr-003.md This example shows a potentially minimized version of a long sequence error message, using '< 7 more >' to indicate omitted elements and improve readability. ```clojure [... < 7 more > 33 ] ^^ should satisfy string? ``` -------------------------------- ### Update Project Packages Source: https://github.com/bhb/expound/blob/master/doc/development.md Checks for outdated project dependencies using `lein-ancient`. Requires `lein-ancient` to be installed. ```bash lein ancient :all ``` ```bash lein with-profile +tools ancient :all ``` -------------------------------- ### Explain 'cat' spec with 'any' predicate Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates a 'cat' spec failing when the element does not satisfy the 'any?' predicate. This spec expects a sequence starting with a keyword and followed by any type. ```clojure (clojure.spec.alpha/explain :cat-spec/any []) ``` -------------------------------- ### Example of Verbose Error Message for Map Matching Source: https://github.com/bhb/expound/blob/master/doc/arch/adr-003.md This example illustrates an unnecessarily long error message when a map matches a user-defined pattern or has a specific problem type. It highlights how nested irrelevant data can inflate the message. ```clojure {:tag ..., :children [{:tag ..., :children [{:tag :group, :props {:on-tap {}}}]}]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ should satisfy nil? ``` -------------------------------- ### Clojure Spec Explain-Data Output Example Source: https://github.com/bhb/expound/blob/master/doc/spec_problems.md Illustrates the output of `s/explain-data` when applied to an entity with an invalid ID, showing two problems for the conditional ID spec. ```clojure { :clojure.spec.alpha/spec :example/entity, :clojure.spec.alpha/value {:id -1} :clojure.spec.alpha/problems '( ;; problem 1 {:path [:id :num], :pred clojure.core/pos-int?, :val -1, :via [:example/entity :example/id], :in [:id]} ;; problem 2 {:path [:id :uuid], :pred clojure.core/uuid?, :val -1, :via [:example/entity :example/id], :in [:id]}) } ``` -------------------------------- ### Explain 'cat' spec with inline 'alt' Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Shows a 'cat' spec with an inline 'alt' combinator failing due to incorrect input. This is similar to the previous example but defines the 'alt' directly within the 'cat'. ```clojure (clojure.spec.alpha/explain :cat-spec/alt-inline []) ``` -------------------------------- ### Clojure Spec Definitions for Example Source: https://github.com/bhb/expound/blob/master/doc/spec_problems.md Defines a spec for an ID that can be either a positive integer or a UUID, and an entity spec that requires this ID. ```clojure (s/def :example/id (s/or :num pos-int? :uuid uuid? )) (s/def :example/entity (s/keys :req-un [:example/id])) ``` -------------------------------- ### Expound formatted spec error message Source: https://github.com/bhb/expound/blob/master/README.md This example shows how Expound transforms a verbose clojure.spec error message into a more readable format, highlighting missing keys and their expected specs. ```text -- Spec failed -------------------- {} should contain keys: :city, :state | key | spec | |========+=========| | :city | string? | |--------+---------| | :state | string? | ``` -------------------------------- ### Expound Error Message Context Display Source: https://github.com/bhb/expound/blob/master/doc/cljtogether/project_update3.md Illustrates how Expound displays specific error locations within the context of an invalid value, using an example of an incorrect string in an integer list. ```clojure {:ids [... "456" ...]}^^^^ should satisfy int? ``` -------------------------------- ### Example of Long Sequence Error Message Source: https://github.com/bhb/expound/blob/master/doc/arch/adr-003.md This snippet demonstrates a verbose error message for long sequences, where repeated '...' values contribute to excessive length. It shows the potential for minimization. ```clojure [... ... ... ... ... ... ... ... 33 ] ^^ should satisfy string? ``` -------------------------------- ### Expound Error Message for Invalid Route Data Source: https://github.com/bhb/expound/blob/master/doc/arch/adr-003.md This is the resulting error message from the Reitit router example when spec validation fails. It shows the route path, the failing spec data, and the specific validation error. ```clojure CompilerException clojure.lang.ExceptionInfo: Invalid route data: -- On route ----------------------- "/api" -- Spec failed -------------------- {:handler ..., :user/roles #{:adminz}} ^^^^^^^ should be one of: `:admin`,`:manager` ``` -------------------------------- ### Leiningen/Boot Dependency Source: https://github.com/bhb/expound/blob/master/README.md Add this dependency to your project.clj or build.boot file to include Expound in your project. ```clojure "expound "0.9.0"" ``` -------------------------------- ### Publish to NPM Source: https://github.com/bhb/expound/blob/master/doc/development.md Publishes the project to NPM. Verify the version in `package.json` and use the appropriate access flag. ```bash npm publish --access=public ``` -------------------------------- ### Configure Expound Printer Options Source: https://github.com/bhb/expound/blob/master/README.md Customize the output of `expound/expound` and `expound-str` using options like `:print-specs?` and `:theme`. These options can be passed directly or set globally. ```clojure (expound/expound :example/place {:city "Denver", :state :CO} {:print-specs? false :theme :figwheel-theme}) ``` ```clojure (set! s/*explain-out* (expound/custom-printer {:show-valid-values? true :print-specs? false :theme :figwheel-theme})) ;; (or alter-var-root - see doc/faq.md) ``` -------------------------------- ### Deploy to Clojars Source: https://github.com/bhb/expound/blob/master/doc/development.md Deploys the project to Clojars. Ensure the version is updated in `project.clj` and use a deploy token. ```bash lein deploy clojars ``` -------------------------------- ### Define and Explain Spec2 Schema with Expound Source: https://github.com/bhb/expound/blob/master/doc/cljtogether/project_update6.md This snippet demonstrates defining a schema using clojure.alpha.spec and then using Expound to explain validation failures for an empty map against that schema. Ensure you have `clojure.alpha.spec` and `expound.alpha2` available. ```clojure (ns example) (require '[clojure.alpha.spec :as s]) (require '[expound.alpha2 :as expound]) (s/def ::street string?) (s/def ::city string?) (s/def ::state string?) ;; simplified (s/def ::zip int?) ;; simplified (s/def ::addr (s/schema [::street ::city ::state ::zip])) (s/def ::id int?) (s/def ::first string?) (s/def ::last string?) (s/def ::user (s/schema [::id ::first ::last ::addr])) (s/def ::movie-times-user (s/select ::user [::id ::addr {::addr [::zip]}])) (s/explain ::movie-times-user {}) ;; {} - failed: (fn [m] (contains? m :example/id)) spec: :example/movie-times-user ;; {} - failed: (fn [m] (contains? m :example/addr)) spec: :example/movie-times-user (expound/expound ::movie-times-user {}) ;;-- Spec failed -------------------- ;; ;; {} ;; ;;should satisfy ;; ;; (fn [m] (contains? m :example/id)) ;; ;;or ;; ;; (fn [m] (contains? m :example/addr)) ;; ;;-- Relevant specs ------- ;; ;;:example/movie-times-user: ;; (clojure.alpha.spec/select ;; :example/user ;; [:example/id :example/addr #:example{:addr [:example/zip]}] ;; ) ;; ;;———————————— ;;Detected 1 error ``` -------------------------------- ### Custom clojure.test/report Override Source: https://github.com/bhb/expound/blob/master/README.md Override the default clojure.test/report function to customize error reporting, especially useful in ClojureScript test runners. This example shows how to handle :error reports. ```clojure (ns pkg.test-runner (:require [clojure.spec.alpha :as s] [clojure.test :as test :refer-macros [run-tests]] [expound.alpha :as expound] ;; require your namespaces here [pkg.namespace-test])) (enable-console-print!) (set! s/*explain-out* expound/printer) ;; (or alter-var-root - see doc/faq.md) ;; We try to preserve the clojure.test output format (defmethod test/report [:cljs.test/default :error] [m] (test/inc-report-counter! :error) (println "\nERROR in" (test/testing-vars-str m)) (when (seq (:testing-contexts (test/get-current-env)))) (println (test/testing-contexts-str))) (when-let [message (:message m)] (println message)) (let [actual (:actual m) ex-data (ex-data actual)] (if (:clojure.spec.alpha/failure ex-data) (do (println "expected:" (pr-str (:expected m))) (print " actual:\n") (print (.-message actual))) (test/print-comparison m)))) ;; run tests, (stest/instrument) either here or in the individual test files. (run-tests 'pkg.namespace-test) ``` -------------------------------- ### Explaining Spec Data with Conformer Source: https://github.com/bhb/expound/blob/master/doc/arch/adr-002.md Shows how to use `s/explain-data` to inspect spec validation results, including problems related to conformers. The output highlights the path, predicate, value, and context of the failure. ```clojure (s/explain-data ::string-AB "AC") ;; #:clojure.spec.alpha{:problems [{:path [:b], :pred #{\B}, :val \C, :via [:expound.problems/string-AB :expound.problems/string-AB-seq], :in [1]}], :spec :expound.problems/string-AB, :value "AC"} ``` -------------------------------- ### Explain 'cat' spec with 'alt' combinator Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a 'cat' spec using an 'alt' combinator, failing when the input does not match the expected sequence of alternatives. Use 'alt' for choices within a sequence. ```clojure (clojure.spec.alpha/explain :cat-spec/alt []) ``` -------------------------------- ### Reitit Router with Expound for Spec Validation Source: https://github.com/bhb/expound/blob/master/doc/arch/adr-003.md This code demonstrates setting up a Reitit router that uses Expound for stringifying spec validation errors. It includes definitions for roles and a router configuration. ```clojure (require '[reitit.core :as r]) (require '[clojure.spec.alpha :as s]) (require '[expound.alpha :as e]) (s/def ::role #{:admin :manager}) (s/def ::roles (s/coll-of ::role :into #{})) (r/router ["/api" {:handler identity ::roles #{:adminz}}] {::rs/explain e/expound-str :validate rs/validate-spec!}) ``` -------------------------------- ### Run Clojure Tests Source: https://github.com/bhb/expound/blob/master/doc/development.md Executes Clojure tests using Leiningen or Kaocha. Offers options for different test runners and watch modes. ```bash lein with-profile +test-common test ``` ```bash lein with-profile +test-common test-refresh :changes-only ``` ```bash clj -Atest:test-deps ``` ```bash bin/kaocha --watch --plugin profiling ``` -------------------------------- ### Configure Expound for Macro Expansion in Clojure Source: https://github.com/bhb/expound/blob/master/doc/compatibility.md Configure Expound for macro expansion in Clojure environments. This is necessary for self-hosted ClojureScript. ```bash clj -Srepro -Sdeps '{:deps {expound/expound {:mvn/version "0.9.0"} org.clojure/test.check {:mvn/version "0.9.0"} org.clojure/clojurescript {:mvn/version "1.10.520"}}}' -e "(require '[expound.alpha :as expound]) (set! clojure.spec.alpha/*explain-out* expound.alpha/printer)" -m cljs.main -re node ``` -------------------------------- ### Print Spec Test Results with Expound Source: https://github.com/bhb/expound/blob/master/README.md Use `expound/explain-results` to print the results from `clojure.spec.test.alpha/check`. This requires importing Expound and Clojure spec test libraries. ```clojure (require '[expound.alpha :as expound] '[clojure.spec.test.alpha :as st] '[clojure.spec.alpha :as s] '[clojure.test.check]) (s/fdef ranged-rand :args (s/and (s/cat :start int? :end int?) #(< (:start %) (:end %))) :ret int? :fn (s/and #(>= (:ret %) (-> % :args :start)) #(< (:ret %) (-> % :args :end)))) (defn ranged-rand "Returns random int in range start <= rand < end" [start end] (+ start (long (rand (- start end))))) (set! s/*explain-out* expound/printer) ;; (or alter-var-root - see doc/faq.md) (expound/explain-results (st/check `ranged-rand)) ``` -------------------------------- ### Explain String Predicate Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a spec failure for a string predicate. The input `:hello` was expected to be a string but was not. ```clojure (clojure.spec.alpha/explain :predicate-messages/string :hello) ``` -------------------------------- ### Generate Namespace Dependency Graph Source: https://github.com/bhb/expound/blob/master/doc/development.md Generates a visual graph of namespace dependencies using `lein hiera`. ```bash lein hiera ``` -------------------------------- ### deps.edn Dependency Source: https://github.com/bhb/expound/blob/master/README.md Include Expound in your project by adding this entry to your deps.edn file. ```clojure expound/expound {:mvn/version "0.9.0"} ``` -------------------------------- ### Run Clojurescript Tests with Karma Source: https://github.com/bhb/expound/blob/master/doc/development.md Executes Clojurescript tests using Karma. Supports both automatic and manual test execution. ```bash lein with-profile test-web cljsbuild auto test ``` ```bash ls ./resources/public/test-web/test.js | entr -s 'sleep 1; bin/tests' ``` -------------------------------- ### Generate Code Coverage Report Source: https://github.com/bhb/expound/blob/master/doc/development.md Generates a code coverage report using Kaocha with the cloverage plugin. Allows exclusion of specific functions. ```bash bin/kaocha --plugin cloverage --cov-exclude-call expound.alpha/def ``` -------------------------------- ### Lint Code with Joker Source: https://github.com/bhb/expound/blob/master/doc/development.md Lints the project's code using the `joker` linter. ```bash ./bin/lint ``` -------------------------------- ### Using Expound Printer with Orchestra Source: https://github.com/bhb/expound/blob/master/README.md Integrate Expound with Orchestra to receive human-optimized error messages for spec checks on `:ret` and `:fn`. Ensure Orchestra and Expound are required and instrumented. ```clojure (require '[orchestra.spec.test :as st]) (s/fdef location :args (s/cat :city :example.place/city :state :example.place/state) :ret string?) (defn location [city state] ;; incorrect implementation nil) (st/instrument) (set! s/*explain-out* expound/printer) ;; (or alter-var-root - see doc/faq.md) (location "Seattle" "WA") ;;ExceptionInfo Call to #'user/location did not conform to spec: ;; form-init3240528896421126128.clj: ;; ;; -- Spec failed -------------------- ;; ;; Return value ;; ;; nil ;; ;; should satisfy ;; ;; string? ;; ;; ------------------------- ;; Detected 1 error ``` -------------------------------- ### Explain Multispec in Compound Spec (Animal) Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a missing spec for a multispec within a compound spec, considering multiple possibilities. The input `#:pet{:type :fish}` did not match either the `expound.sample/pet` or `expound.sample/animal` multimethods. ```clojure (clojure.spec.alpha/explain :multispec-in-compound-spec/pet2 #:pet{:type :fish}) ``` -------------------------------- ### Explain Multispec in Compound Spec (Pet) Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a missing spec for a multispec within a compound spec. The input `#:pet{:type :fish}` could not be matched by the `expound.sample/pet` multimethod. ```clojure (clojure.spec.alpha/explain :multispec-in-compound-spec/pet1 #:pet{:type :fish}) ``` -------------------------------- ### Explain Key-Value or String Spec Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates a spec failure where a map is expected to contain a specific key, but it's missing. Expound highlights the missing key and the expected spec. ```clojure (clojure.spec.alpha/explain :cat-wrapped-in-or-spec/kv-or-string {foo hi}) ``` -------------------------------- ### Explain Or Spec String or Int Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a failure when a value is neither an integer nor a string, as defined by an 'or' spec. ```clojure (clojure.spec.alpha/explain :or-spec/str-or-int :kw) ``` -------------------------------- ### Explain String Type Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a failure when a value does not satisfy the string? predicate. ```clojure (clojure.spec.alpha/explain string? 1) ``` -------------------------------- ### Explain Email Predicate Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a spec failure for a custom email predicate. The input `"sally@"` did not match the defined email regex. ```clojure (clojure.spec.alpha/explain :predicate-messages/email sally@) ``` -------------------------------- ### Explain OR Spec with String or Vector Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a spec failure for an OR specification. The input `1` failed to satisfy either the string or vector predicate. ```clojure (clojure.spec.alpha/explain (s/or :s :predicate-messages/string :v :predicate-messages/vector) 1) ``` -------------------------------- ### Explain 'or' spec with missing keys Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates an 'or' spec failing when required keys are missing. Use this to validate data structures with alternative valid shapes. ```clojure (clojure.spec.alpha/explain (s/or :m-with-str1 (s/keys :req [:or-spec/str]) :m-with-int2 (s/keys :req [:or-spec/str])) {}) ``` -------------------------------- ### Replacing `clojure.spec.alpha` functions Source: https://github.com/bhb/expound/blob/master/README.md Replace calls to `clojure.spec.alpha/explain` with `expound.alpha/expound` and `clojure.spec.alpha/explain-str` with `expound.alpha/expound-str`. This snippet shows how to use `expound/expound` with a map spec. ```clojure (require '[clojure.spec.alpha :as s]) (require '[expound.alpha :as expound]) (s/def :example.place/city string?) (s/def :example.place/state string?) (s/def :example/place (s/keys :req-un [:example.place/city :example.place/state])) (expound/expound :example/place {:city "Denver", :state :CO} {:print-specs? false}) ;; -- Spec failed -------------------- ;; {:city ..., :state :CO} ;; ^^^ ;; should satisfy ;; string? ;; ------------------------- ;; Detected 1 error ``` -------------------------------- ### Explain Collection of Function Specs with Exception Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports an exception when a function spec within a collection fails. The input `[]` caused an exception with arguments `0`. ```clojure (clojure.spec.alpha/explain (s/coll-of (s/fspec :args (s/cat :x int?) :ret int?)) [[]]) ``` -------------------------------- ### Explain Integer or String Spec Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Shows a failure in a spec that allows either an integer or a string. Expound highlights the value that failed to satisfy either condition and lists the alternative specs. ```clojure (clojure.spec.alpha/explain :alt-spec/int-or-str [:hi]) ``` -------------------------------- ### Check for Inconsistent Aliases Source: https://github.com/bhb/expound/blob/master/doc/development.md A script to identify namespace aliases that are not consistent across the codebase. ```bash ./bin/inconsistent-aliases ``` -------------------------------- ### Control Showing Valid Values in Output Source: https://github.com/bhb/expound/blob/master/README.md Configure Expound to either omit valid values (default) or display them using the `:show-valid-values?` option in `expound/custom-printer`. ```clojure (set! s/*explain-out* expound/printer) ;; (or alter-var-root - see doc/faq.md) (s/explain :example/place {:city "Denver" :state :CO :country "USA"}) ``` ```clojure (set! s/*explain-out* (expound/custom-printer {:show-valid-values? true})) ;; (or alter-var-root - see doc/faq.md) (s/explain :example/place {:city "Denver" :state :CO :country "USA"}) ``` -------------------------------- ### Explain OR Spec with Multiple Predicates Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a spec failure for an OR specification with multiple conditions. The input `foo` did not satisfy `pos-int?`, `vector?`, or the string predicate. ```clojure (clojure.spec.alpha/explain (s/or :p pos-int? :s :predicate-messages/string :v vector?) (quote foo)) ``` -------------------------------- ### Grouping Alternatives in Specs Source: https://github.com/bhb/expound/blob/master/doc/comparison.md Expound groups alternatives, making it clear which of the possible specs a value failed to satisfy. This is useful for specs defined with `s/or`. ```clojure (s/def :address.west-coast/zip (s/or :str clojure.core/string? :num clojure.core/pos-int?)) ``` ```clojure ":98109" ``` ```clojure ":98109" - failed: string? at: [:str] spec: :address.west-coast/zip ":98109" - failed: pos-int? at: [:num] spec: :address.west-coast/zip ``` ```clojure -- Spec failed -------------------- :98109 should satisfy string? or pos-int? ------------------------- Detected 1 error ``` -------------------------------- ### Explain 'and' spec with empty string Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Shows an 'and' spec failing when an empty string is provided, as it does not satisfy the non-empty string requirement. Use 'and' to combine multiple predicates. ```clojure (clojure.spec.alpha/explain :and-spec/name ) ``` -------------------------------- ### Racket Error Message Convention Source: https://github.com/bhb/expound/blob/master/doc/prior_art.md Shows the standard format for Racket error messages, including source location, error name, message, and detailed fields. ```Racket ‹srcloc›: ‹name›: ‹message›; ‹continued-message› ... ‹field›: ‹detail› ... ``` -------------------------------- ### Explain String Type Spec Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a failure when a non-string value is provided to a spec expecting a string. ```clojure (clojure.spec.alpha/explain :duplicate-preds/str-or-str 1) ``` -------------------------------- ### Instrument Adder Syntax Error Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Shows a syntax error within function arguments during instrumentation, where an unexpected element is present. Expound points out the problematic syntax and the expected structure. ```clojure (test-instrument-adder 1) ``` -------------------------------- ### Explain Map Spec Key Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates a failure when a map does not contain the required keys as defined by the spec. ```clojure (clojure.spec.alpha/explain :or-spec/m-with-str-or-int {}) ``` -------------------------------- ### Instrument Adder Spec Failure (Empty String) Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a spec failure when calling an instrumented function with an incorrect argument type (empty string instead of an integer). Expound shows the function arguments and the expected type. ```clojure (format-spec-err (test-instrument-adder :x)) ``` -------------------------------- ### Instrument Adder Function Arguments and Return Value Spec Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates a complex spec failure involving both function arguments and the return value. Expound provides a detailed view of the arguments, return value, and the failing condition. ```clojure (test-instrument-adder 1 0) ``` -------------------------------- ### Explain Nilable Tag Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a failure when a value is neither nil nor present in the allowed set of keywords for a nilable spec. ```clojure (clojure.spec.alpha/explain :set-based-spec/nilable-tag :baz) ``` -------------------------------- ### Explain Collection of Function Specs with Argument Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates an error when a function within a collection fails its argument assertions. ```clojure (clojure.spec.alpha/explain (s/coll-of :fspec-test/div) [my-div]) ``` -------------------------------- ### Instrument Adder Spec Failure (Argument Type) Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates a spec failure during function instrumentation where an argument does not match the expected type. Expound details the function arguments and the expected type. ```clojure (test-instrument-adder :x) ``` -------------------------------- ### Explain 'cat' spec with incorrect alternative type Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates a 'cat' spec failing when the provided type does not match any of the allowed alternatives. This spec expects a :type that is either :bar or :foo. ```clojure (clojure.spec.alpha/explain :cat-spec/set []) ``` -------------------------------- ### Explain Collection of Function Specs with Custom Predicate Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates an error when a function within a collection fails a custom predicate check on its arguments and return value. ```clojure (clojure.spec.alpha/explain (s/coll-of :fspec-fn-test/minus) [my-minus]) ``` -------------------------------- ### Explain Function Custom Predicate Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates a failure when a function's arguments and return value do not satisfy a custom predicate defined in the spec. ```clojure (clojure.spec.alpha/explain :fspec-fn-test/minus my-minus) ``` -------------------------------- ### Explain Or Spec with Set Membership Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a failure when a value is not present in any of the sets defined within an 'or' specification. ```clojure (clojure.spec.alpha/explain (s/or :letters #{a b} :ints #{1 2}) 50) ``` -------------------------------- ### Explain 'coll-of' spec with minimum count Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a 'coll-of' spec failing when the collection does not meet the minimum count requirement. This spec requires at least 10 integers. ```clojure (clojure.spec.alpha/explain :coll-of-spec/big-int-coll []) ``` -------------------------------- ### Explain Collection of Function Specs Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a function spec failure within a collection. The input `#{}` did not satisfy the expected `int?` return type for the function spec. ```clojure (clojure.spec.alpha/explain (s/coll-of (s/fspec :args (s/cat :x int?) :ret int?)) #{}) ``` -------------------------------- ### Explain Set-of-One Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Shows a failure when a value is not the single expected value in a set. ```clojure (clojure.spec.alpha/explain :set-based-spec/set-of-one :baz) ``` -------------------------------- ### ClojureScript browser error formatter Source: https://github.com/bhb/expound/blob/master/README.md A custom formatter for Chrome devtools that uses Expound to format `ExceptionInfo` objects in the browser console. This requires setting up a global handler to catch errors and call `repl/error->str`. ```clojure (require '[cljs.repl :as repl]) (require '[clojure.spec.alpha :as s]) (require '[expound.alpha :as expound]) (set! s/*explain-out* expound/printer) (def devtools-error-formatter "Uses cljs.repl utilities to format ExceptionInfo objects in Chrome devtools console." #js{:header (fn [object _config] (when (instance? ExceptionInfo object) (let [message (some->> (repl/error->str object) (re-find #"[^ ]+"))] #js["span" message]))) :hasBody (constantly true) :body (fn [object _config] #js["div" (repl/error->str object)])}) (defonce _ (some-> js/window.devtoolsFormatters (.unshift devtools-error-formatter))) ``` -------------------------------- ### Explain Collection of Or Spec Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates a failure within a collection where elements are expected to satisfy a string or int 'or' spec, but do not. ```clojure (clojure.spec.alpha/explain :or-spec/vals [0 hi :kw bye]) ``` -------------------------------- ### Check Function Spec Failure with Arguments and Return Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a function spec failure with details on arguments and return values. The call `( 0 0)` failed its spec, with the arguments `{:x 0, :y 0}` and return value `0` not satisfying the condition `(< x ret)`. ```clojure == Checked ======================== -- Function spec failed ----------- ( 0 0) failed spec. Function arguments and return value {:args {:x 0, :y 0}, :ret 0} should satisfy (fn [%] (let [x (-> % :args :x) y (-> % :args :y) ret (-> % :ret)] (< x ret))) ``` -------------------------------- ### Explain Set-Based Spec One-or-Two Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates a failure where an element in a collection does not match any of the expected values in an 'or' specification. ```clojure (clojure.spec.alpha/explain :set-based-spec/one-or-two [:three]) ``` -------------------------------- ### Instrument Adder Return Value Spec Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a spec failure related to the return value of an instrumented function. Expound shows the actual return value and the spec it should have satisfied. ```clojure (test-instrument-adder -1 -2) ``` -------------------------------- ### Explain 'and' spec with mixed types in collection Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates an 'and' spec failing when a collection contains elements that do not match the required predicates. This spec expects a collection of non-empty strings. ```clojure (clojure.spec.alpha/explain :and-spec/names [bob sally 1]) ``` -------------------------------- ### Explain Recursive Spec Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a failure in a recursive spec with nested structures. Shows how Expound pinpoints the exact location of the failure within the nested data. ```clojure (clojure.spec.alpha/explain :recursive-spec/el {:tag :group, :children [{:tag :group, :children [{:tag :group, :props {:on-tap {}}}]}]}) ``` -------------------------------- ### Use Built-in Predicates with Error Messages Source: https://github.com/bhb/expound/blob/master/README.md Expound provides default error messages for common type-like predicates. Use `expound/expound` with these built-in specs for clearer feedback. ```clojure (expound/expound :expound.specs/pos-int -1) ``` -------------------------------- ### Explain 'cat' spec with missing keyword Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Shows a 'cat' spec failing due to a missing keyword. 'cat' is used for sequential destructuring with named elements. ```clojure (clojure.spec.alpha/explain :cat-spec/kw []) ``` -------------------------------- ### Missing Keys in Map Validation Source: https://github.com/bhb/expound/blob/master/doc/comparison.md When a key is missing from a map, Expound displays the associated spec, making it easier to understand the validation failure. This is helpful for ensuring all required keys are present. ```clojure (s/def :address.west-coast/city clojure.core/string?) (s/def :address.west-coast/state #{"CA" "WA" "OR"}) (s/def :app/address (s/keys :req-un [:address.west-coast/city :address.west-coast/state])) ``` ```clojure {} ``` ```clojure {} - failed: (contains? % :city) spec: :app/address {} - failed: (contains? % :state) spec: :app/address ``` ```clojure -- Spec failed -------------------- {} should contain keys: :city, :state | key | spec | |========+===================| | :city | string? | |--------+-------------------| | :state | #{"CA" "WA" "OR"} | ------------------------- Detected 1 error ``` -------------------------------- ### Provide Custom Function for Displaying Invalid Values Source: https://github.com/bhb/expound/blob/master/README.md Use the `:value-str-fn` option with `expound/custom-printer` to define a custom function for formatting how invalid values are displayed in error messages. ```clojure (s/fdef my-value-str :args (s/cat :spec-name (s/nilable #{:args :fn :ret}) :form any? :path :expound/path :value any?) :ret string?) (defn my-value-str [_spec-name form path value] (str "In context: " (pr-str form) "\n" "Invalid value: " (pr-str value))) (set! s/*explain-out* (expound/custom-printer {:value-str-fn my-value-str})) ;; (or alter-var-root - see doc/faq.md) (s/explain :example/place {:city "Denver" :state :CO :country "USA"}) ``` -------------------------------- ### Explain Nested Collection String Type Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Illustrates a failure within a nested collection where an element does not satisfy the string? predicate. ```clojure (clojure.spec.alpha/explain :nested-type-based-spec/strs [one two 33]) ``` -------------------------------- ### Explain Or Spec with Coll Predicate Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Shows a failure when a value does not satisfy the 'coll?' predicate within a more complex 'or' specification. ```clojure (clojure.spec.alpha/explain (s/or :strs (s/coll-of string?) :ints (s/coll-of int?)) 50) ``` -------------------------------- ### Explain Nested Collection Int Type Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Shows a failure in a nested collection where elements are expected to be integers but are not. ```clojure (clojure.spec.alpha/explain :nested-type-based-spec-special-summary-string/ints [1 2 ...]) ``` -------------------------------- ### Predicate Descriptions for Validation Source: https://github.com/bhb/expound/blob/master/doc/comparison.md Expound displays custom predicate descriptions, improving clarity when a value fails a custom validation function. Use this to provide user-friendly messages for complex validation logic. ```clojure (def email-regex #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,63}$\") (defn valid-email? [s] (re-matches email-regex s)) (s/def :app.user/email (s/and string? valid-email?)) (expound/defmsg :app.user/email "should be a valid email address") ``` ```clojure "@example.com" ``` ```clojure "@example.com" - failed: valid-email? spec: :app.user/email ``` ```clojure -- Spec failed -------------------- "@example.com" should be a valid email address ------------------------- Detected 1 error ``` -------------------------------- ### Explain Collection of Function Specs with Return Value Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Shows an error when a function within a collection returns a value that does not satisfy its spec. ```clojure (clojure.spec.alpha/explain (s/coll-of :fspec-ret-test/plus) [my-plus]) ``` -------------------------------- ### Explain Score Range Predicate Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a spec failure for a custom score range predicate. The input `101` was outside the expected range of 0 to 100. ```clojure (clojure.spec.alpha/explain :predicate-messages/score 101) ``` -------------------------------- ### Explain Function Return Value Spec Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Demonstrates a failure when a function's return value does not satisfy the specified return type. ```clojure (clojure.spec.alpha/explain :fspec-ret-test/plus my-plus) ``` -------------------------------- ### Check Function Spec Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a failure when checking a function's spec. The function `expound.sample/some-func` is not defined, leading to a check failure. ```clojure == Checked expound.sample/some-func ========= Failed to check function. expound.sample/some-func is not defined ``` -------------------------------- ### Set-Based Spec Mismatch Source: https://github.com/bhb/expound/blob/master/doc/comparison.md Expound lists possible values when a value doesn't match a set-based spec, aiding in debugging. Use this when validating against a predefined set of allowed values. ```clojure (s/def :address.west-coast/city clojure.core/string?) (s/def :address.west-coast/state #{"CA" "WA" "OR"}) (s/def :app/address (s/keys :req-un [:address.west-coast/city :address.west-coast/state])) ``` ```clojure {:city "Seattle", :state "ID"} ``` ```clojure "ID" - failed: #{"CA" "WA" "OR"} in: [:state] at: [:state] spec: :address.west-coast/state ``` ```clojure -- Spec failed -------------------- {:city ..., :state "ID"} ^^^^ should be one of: "CA", "OR", "WA" ------------------------- Detected 1 error ``` -------------------------------- ### Explain Set-Based Spec Tag Failure Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Shows a failure when a tag value is not present in the allowed set of keywords. ```clojure (clojure.spec.alpha/explain :set-based-spec/tag :baz) ``` -------------------------------- ### Sequence Validation: Too Few Elements Source: https://github.com/bhb/expound/blob/master/doc/comparison.md Expound describes what elements are missing when a sequence has too few elements, indicating the expected next element and its spec. This is useful for validating sequences with a fixed structure. ```clojure (s/def :app/ingredient (s/cat :quantity clojure.core/number? :unit clojure.core/keyword?)) ``` ```clojure [100] ``` ```clojure () - failed: Insufficient input at: [:unit] spec: :app/ingredient ``` ```clojure -- Syntax error ------------------- [100] should have additional elements. The next element ":unit" should satisfy keyword? ------------------------- Detected 1 error ``` -------------------------------- ### Check Spec Failure with Conformed Value Source: https://github.com/bhb/expound/blob/master/test/expected_sample_out.txt Reports a spec failure after value conformation. The input `[1 0]` was conformed to `{:x 1, :y 0}` but failed to satisfy the relevant spec. ```clojure -- Spec failed -------------------- [1 0] when conformed as {:x 1, :y 0} should satisfy ```