Comments (13)
Thanks for the feedback and for using Expound! 😄
Unfortunately, alter-var-root
doesn't always work either: namely, in the case of using spec and Expound inside the Clojure REPL. I've had questions about this - users try to use alter-var-root
and then are surprised when it doesn't work (but set!
does work in this case). As a result, I think it's good to mention both alter-var-root
and set!
and discuss when they are appropriate (and probably default to set!
, since it's appropriate for most use cases).
The README currently includes this section:
If you are enabling Expound in a non-REPL environment, remember that set! will only change s/explain-out in the current thread. If your program spawns additional threads (e.g. a web server), you can set s/explain-out for all threads with (alter-var-root #'s/explain-out (constantly expound/printer)). This won't work (and is not necessary) in CLJS.
Using set! will also not work within an uberjar.
Unfortunately, it sounds like you still got bitten by this, so the docs should probably be reorganized or rewritten to be clearer. I suspect other users will run into similar problems. In your opinion, what would be a good way to improve the docs here?
from expound.
Thanks for reporting this! What version of Clojure and clojure.spec
are you using?
from expound.
Are you running this at the REPL or in some other way?
from expound.
1.9.0-alpha17. Strangely, it works in tests and in the REPL but fails when run from a -main
inside an Uberjar.
from expound.
Thanks for the info! The following works
lein new expound-client-command-line
- Add
:main expound-client-command-line.core
to project.clj - Edit
src/expound_client_command_line/core.clj
to be
(ns expound-client-command-line.core
(:require [clojure.spec.alpha :as s]
[expound.alpha :as expound]))
(s/def ::name string?)
(defn -main []
(set! s/*explain-out* expound/printer)
(s/explain ::name 1))
I will see if I can reproduce with an uberjar.
from expound.
@devth I can reproduce with an uberjar. Unfortunately, I've been looking for a concise explanation of why this won't work with an uberjar and I haven't found anything yet, but my googling may be failing me. I'd be happy to add a note to the instructions, but I'd like to have a link or at least an explanation.
Can you talk more about your use case? In most cases, I would not expect the final uberjar artifact to be using expound (it's generally a dev-time library). I suppose one could use expound to, say, display error messages for an API, but in this case, would using binding
be sufficient to localize the effect of changing *explain-out*
?
from expound.
@bhb thanks. I was partly trying to figure out why set!
didn't work and whether I was just missing something. The set!
docs weren't super clear, and now they're all the more confusing.
Keeping it in an uberjar was for convenience and we would have removed it eventually. I'll remove it now instead. And yes, binding would be perfectly usable in an uberjar since there's a natural entrypoint to bind from.
from expound.
Dynamic vars have to be bound with binding
before you set!
values to them.
But, in most cases you don't have to do it yourself in the REPL for dynamic vars defined in Clojure core because Clojure REPL does that for you before getting started (cf. https://github.com/clojure/clojure/blob/master/src/clj/clojure/main.clj#L71-L89).
In this case, I think something like the following should work:
(binding [s/*explain-out* expound/printer]
(s/explain ::name 1))
Note that this might not work if the body of the binding
form would be executed in other thread.
from expound.
@athos Ah, thank you for the explanation! This all makes more sense now.
@devth Thanks again for reporting this. I certainly did not understand all the subtleties of using set!
. But since set!
works in the contexts that I would expect clients to use Expound (namely, at dev time), I'm leaning towards leaving the documentation as-is for now. If this continues to be a source of confusion, I'll reconsider modifying the documentation to either only recommend using binding
or adding a note about when set!
won't work.
from expound.
We just got bitten by that as well, might be useful to point it out in the docs!
We're using it in dev and testing only - but we use tomcat during testing, so our artifact is an uberjar.
Would alter-var-root
be a valid alternative? It looks like Pallet used it at some point:
(From https://stackoverflow.com/a/16448108/7182237, pasting for convenience)
(defn force-slf4j
"The repl task brings in commons-logging, which messes up our logging
configuration. This is an attempt to restore sanity."
[]
(binding [*ns* (the-ns 'clojure.tools.logging.slf4j)]
(alter-var-root
#'clojure.tools.logging/*logger-factory*
(constantly (clojure.tools.logging.slf4j/load-factory)))))
from expound.
Unfortunately, alter-var-root doesn't always work either
Oh, :(
At least the failure mode is not so bad (set! throws an exception and halts tomcat), and if I'm in a REPL I imagine I can rebind it myself.
To be fair, I went straight to the orchestra section and completely missed this paragraph. Even now, knowing it was there, I still had a bit of trouble finding it.
It might be the case that the title could have been more elaborate (e.g. just like "Using orchestra", we could have "Using expound as the default printer for clojure.spec/orchestra"), or perhaps we need a reference on the orchestra section (e.g. "The same binding restrictions apply (explain-out link)").
I think it's good to mention both alter-var-root and set! and discuss when they are appropriate (and probably default to set!, since it's appropriate for most use cases).
I agree that it might be useful to have them described in more detail - either with a more explicit section or with comments in the code snippets.
Thanks for both the quick response and this glorious lib!
from expound.
(e.g. "The same binding restrictions apply (explain-out link)")
Good idea! I'll leave this open as a doc issue - I may also explore whether I can just figure out an API that doesn't require users dive into the details of set!
and alter-var-root
entirely by intelligently installing Expound. We'll see.
from expound.
Closing with #142
from expound.
Related Issues (20)
- Error reports returned as :cause string in an exception when produced by instrumentation within generative testing HOT 11
- allow passing options map to expound/expound-str HOT 1
- Improve grouping of spec errors HOT 2
- Unnecessary dependency on `cider-nrepl` HOT 1
- Regression of #3 HOT 4
- Easier editing of error messages
- `printer` has invalid spec HOT 2
- "Cannot convert path" on instrumentation failures in the wild HOT 4
- (cljs.spec.test.alpha/instrument) breaks expound due to wrong arity HOT 4
- should expound work anywhere s/explain works? - clojurescript error HOT 7
- Error in :ret check when using with Orchestra 2020.07.12-1 HOT 5
- Internal error in `lift-singleton-groups` when having a datomic db value in fn args HOT 13
- Crash bug when printing, if a datomic db is present and the spec fails HOT 19
- Feature inquiry: a convenience function for validating a value against a spec HOT 4
- Wrapped `s/keys` does not properly display unqualified keyword specs HOT 5
- ClassCastException from `expound-str` when running in AWS Lambda HOT 9
- Small *print-length* and/or *print-level* sometimes yield NPE HOT 5
- PersistentList cannot be cast to class Named HOT 3
- proposal : defmsg equivalent for arbitrary predicates HOT 15
- optional include location of the spec error in the message. HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from expound.