This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-12
Channels
- # adventofcode (112)
- # architecture (1)
- # beginners (55)
- # boot (26)
- # cider (19)
- # cljs-dev (19)
- # cljsjs (1)
- # cljsrn (7)
- # clojure (140)
- # clojure-android (3)
- # clojure-austin (3)
- # clojure-china (3)
- # clojure-gamedev (1)
- # clojure-greece (43)
- # clojure-spec (75)
- # clojure-sweden (5)
- # clojure-uk (21)
- # clojurescript (66)
- # core-async (2)
- # core-logic (1)
- # cursive (63)
- # datascript (5)
- # datomic (4)
- # devcards (2)
- # duct (13)
- # editors (5)
- # emacs (9)
- # figwheel (4)
- # fulcro (42)
- # graphql (25)
- # immutant (7)
- # jobs (29)
- # leiningen (13)
- # lumo (7)
- # numerical-computing (3)
- # off-topic (22)
- # om (2)
- # onyx (25)
- # pedestal (3)
- # re-frame (14)
- # reagent (20)
- # remote-jobs (1)
- # ring-swagger (3)
- # rum (12)
- # shadow-cljs (9)
- # uncomplicate (1)
- # unrepl (6)
As you might already see it on the Clojure ML, I just released Pinpointer, a clojure.spec error reporter similar to Expound, Inspectable, etc https://github.com/athos/Pinpointer
Pinpointer formats (and even colorizes!) spec errors in a human-readable way. The difference between Expound and Pinpointer is very subtle from the outside perspective, but Pinpointer is based on a systematic error analysis rather than heuristic approaches, and this makes it possible to report more complicated errors, such that s/conformer would transform part of the input value.
@athos I tried pinpointer and it gave up on my complex error, it just used explain as a fallback. Under what circumstances does it do that?
Thank you for giving a try to Pinpointer, @stathissideris! 😆
By default, Pinpointer falls back to s/explain
if something bad happens during the error analysis. That mechanism exists to prevent Pinpointer itself from ruining the original spec error info.
If you would like to turn off the fallback behavior, call pinpoint
with the option {:fallback-on-error false}
like (pinpoint <spec> <input> {:fallback-on-error false})
ok 🙂 in my case I have a pretty loose spec that describes a DSL, so if an expression is wrong, the errors include a lot or different options
because the actual error is one of many things that can go wrong
alright, I’ll try again with this option and see what happens
thanks!
can pinpointer/expound/etc… handle exceptions with spec errors in them?
or would I need to hook into the REPLs exception printer?
In a re-frame CLJS app, my app-db holds entries created by multiple parts of my system. I want to check total validity at start of each re-frame event. So, I have (s/def ::db (s/merge :ns1/db-keys :ns2/db-keys ,,,))
in a central db.cljs
file and I validate it in each event.
Most of these parts are small and can be reasonably each held by a single file holding its specs, subs, and events.
But, this creates a problem. The events need to require the namespace of the merged spec, while that namespace needs the namespaces of each part. What is the cleanest way to tastefully break this namespace circularity?
Ok… partly wanting this for exceptions integrant raises from pre-init-spec
… but it looks like integrant actually calls s/explain-out
to generate the message in the exception so it does indeed work
Yes, s/*explain-out*
plugin mechanism should handle exceptions well.
If you rather want something like clojure.repl/pst
, pinpointer.core/ppt
would be useful.
What is the recommended approach for shared specs in several projects? One solution is to make the spec a separate project and then require it.
I’ve been curious about the same. I guess the options are 1) share a project 2) serialize to some other format which obv. limits what you can do in spec.
Probably going to use a project, on the plus side I get versioned specs
1) monorepo 2) shared lib 3) send/receive as edn (you’d need to make sure specs are cljs compatible, if sharing with ui)
We have a separate repo for specs shared between the client and server (edn). It also contains common functions shared between the two, defs, etc.
Thanks for your input, quite helpfull
But I am not completely happy with that idea
why not?
I suspect it is the best solution, but I am worried about code reloading and such. -- I will just have to try it out
@andreas862 don’t forget about the leiningen checkouts setting (if that’s what you’re using)
it allows you to hack on multiple non-deployed projects in parallel
@stathissideris ah, that is a nice feature!
🙂 @andreas862 https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#checkout-dependencies
Perhaps I should save my future self a lot of time and read the documentation...
Thank you
for putting a spec on a def
'd var, is the standard way to have a fspec on a self-invoking function?
not sure I understand what "putting a spec on a def'd var" means. I'm guessing the answer isn't just "use fdef"?
or do you mean a var that's defined to be something other than a function? if so then specing it isn't supported
e.g., (def ^:private keys-validators (events-schema->keys-validators events-schema))
or
(def ^:private refinements
(merge user-defined-refinements normalized-base-refinements))
spec is meant for validating ranges of possibilities, a def'd var is "permanent" in clojure land. but yeah putting your right hand side inside a function and then fdefing that would make the most sense to me
mm, ok. i'll try that. i think last time i tried it couldn't get it to work with anonymous functions (and wasn't really excited about polluting the global namespace with another defn
)
I mean seeing as this is all only happening once you could just do (def foo (s/assert ::spec (your code here)))
How does one do or in spec, I've tried googling
(s/explain (s/or :k1 (s/coll-of ::ar ::ar)
:k2 (s/coll-of ::ar ::kr)) [(AudioSignal. 1) (ControlSignal. 1)])
I also don't need these keys, but this function is probably wrong. Im makeing a transpiler to a language that has it's own dispatch functions, and since I'm automatically generating the metadata, I end up with different possibilites. Essentally, I'd want to be able to say; this vector can be a sequence of specs ::x ::y or sequence of specs ::foo ::bar.troughout the ocean of functions I want to spec, they can be tuple/octet or whatever number of possibilites...
probably want to look at the regex specs (cat * + ? alt)
if I read what you want to do there for example you could say (s/cat :x ::ar :y (s/alt :a ::ar :k ::kr))
to match sequential collections that start with ar and then have ar or kr. x, y, a, and k are all made up keys that affect the conformed result
anything sequential
seq, vector, list
ok nice, this is actually for the input parameters so it's importent, I'm tempted to do this check at the very beginning of my functions.
they are most commonly used in s/fdef to spec args to functions
so that is a good match
yes I may end up doing that, it's just this instrument function that I'm skeptical of, but I should not be. I want immediate error in runtime on wrong spec, or no matching patterns of a provided arguments, it's kinda pattern matching, therefore looking at or
s/assert might be useful too
On extra question since I'm rambling, is there a way to have any effect on the error message
In: [1] val: #object[csound.core.ControlSignal] fails spec: :csound.core/ar at: [:k1 :0] predicate: audio-signal?
I'm in clojurescript and I know that the object has keys which could help the user locate his problem, as this could be within a nested ast.
s/explain-data
gives you a structure you can get useful stuff out of, and there are some libs for transforming that into something that could be useful for you
Thanks @U3DAE8HMG
Or explain has it too, just didn't consider takeing advantage of that and throw my own error message, suited to help the user find the spec mismatch.
pssst @U0CAUAKCG whatcha doing with csound? Looks cool
Who's asking @U0MF00YRX? I'm working on some interoperability between clojurescript and csound, mainly transpiler, that would be a good start, already been live-coding with this combination for few years
Oh awesome @U0CAUAKCG! I'm trying to do some similar stuff with clojurescript/supercollider. I tried using Overtone for a bit, but found that the startup time is too painful, especially when I tried running on a Raspberry Pi