Fork me on GitHub
#clojure-spec
<
2016-10-05
>
mpenet07:10:14

Is there a workaround to http://dev.clojure.org/jira/browse/CLJ-2033 for un-namespaced keys ?

mpenet07:10:21

I just hit this too

mpenet07:10:45

it makes s/merge a bit useless tbh, not sure why it's not considered a bug

mpenet07:10:59

I guess a workaround would be to do the composition at a higher level, and not rely on spec/merge for merging specs like this, which is... odd

mpenet07:10:29

and the fact that it's macros all the way down makes this workaround also a bit hairy

jmglov08:10:27

Is it possible to spec protocols in any way?

jmglov08:10:42

Or objects that satisfy them?

mpenet11:10:17

I think it's encouraged to wrap protocol fn invocation, so you can instrument/spec the wrapper fn. otherwise if you mean spec predicate it's just #(satisfies? %), possibly with (s/spec pred :gen ... ) if you want to have the gen part

odinodin11:10:13

Anyone used spec with DataScript? Need tips on how to deal with the fact that entities are not maps, and specifically how to get the same functionality as clojure.spec/keys but for Datascript entities

misha11:10:45

@odinodin what do you mean by "not maps"? pull pretty much returns maps.

misha11:10:21

what exactly do you want to cover with spec?

odinodin11:10:46

I have a function that takes DataScript entities

odinodin11:10:16

I'd rather avoid creating maps from entities, and just use entities directly

misha11:10:58

oh, you mean thing returned by d/entity? no idea : )

Yehonathan Sharvit12:10:38

Is it possible to define a spec that references itself in the definition - like in Context-Free Grammars?

Alex Miller (Clojure team)12:10:23

Sure, via it's registered keyword

Alex Miller (Clojure team)12:10:49

Recursive and mutually recursive specs are fine

Yehonathan Sharvit12:10:10

Could you share an example?

Alex Miller (Clojure team)12:10:44

There are several in clojure.core.specs - destructuring is recursive

Alex Miller (Clojure team)12:10:11

Some of the ns stuff with prefix lists , etc

Alex Miller (Clojure team)12:10:21

::prefix-list there is self-recursive

Alex Miller (Clojure team)12:10:19

::binding-form can be ::seq-binding-form or ::map-binding-form, which can both include ::binding-form

Yehonathan Sharvit12:10:14

I’m looking at it

Alex Miller (Clojure team)12:10:46

A really good example to try is just a simple tree of leaf and branch

Alex Miller (Clojure team)12:10:18

Where branches can contain either leaf or branch

mlimotte13:10:18

What's the best way to trigger clojure.spec tests with lein test? I.e. I have a namesapce with (stest/check (stest/enumerate-namespace 'wwai.common.util.instant)), I want it run those checks when I do lein test. I'm really using expectations, but if I see how to make it work with standard test, I should be able to adapt from their.

ag16:10:49

@mlimotte clojure.test.check’s defscpec worked for me

jrheard16:10:46

@ag i’d love to see an example of that on github if you have one, np if not, just figured i’d check 🙂

mlimotte18:10:40

I came up with this hack, which kind of works, although the output in the error case, isn't very friendly:

(defmacro is-result-ok?
  [result]
  `(is (not (:failure (first ~result)))))

(deftest auto
  (doseq [spec-fn-sym (stest/enumerate-namespace 'wwai.common.util.instant)]
    (is-result-ok? (stest/check spec-fn-sym))))

mlimotte18:10:05

I looked at defspec, but didn't see how to make it work with stest/check.

jrheard18:10:16

me neither!

luxbock18:10:59

what's the idiomatic way to express lack of arguments for a function with fdef?

luxbock18:10:53

just empty? should do I guess

luxbock18:10:52

what's the benefit over just using empty?

bfabry18:10:34

nothing afaik, it's just that s/cat is the normal way to start specifying :args

bfabry19:10:34

instrument does not check return values

bfabry19:10:33

you're probably looking for clojure.spec.test/check

bfabry19:10:16

it runs the function a bunch of times with generated args (in this case always nothing) and checks the result conforms to :ret and that any supplied :fn relationship between :args and :ret is true

bfabry19:10:32

boot.user=> (s/def ::number int?)
:boot.user/number
boot.user=> (s/def ::number-list (s/coll-of ::number :min-count 1))
:boot.user/number-list
boot.user=> (s/fdef foobar
       #_=>         :args (s/cat)
       #_=>         :ret ::number-list)
boot.user/foobar
boot.user=> (defn foobar [] [])
#'boot.user/foobar
boot.user=> (clojure.spec.test/check `foobar)
({:spec #object[clojure.spec$fspec_impl$reify__13891 0x222df61e "clojure.spec$fspec_impl$reify__13891@222df61e"], :clojure.spec.test.check/ret {:result #error {
 :cause "Specification-based check failed"
 :data {:clojure.spec/problems [{:path [:ret], :pred (clojure.core/<= 1 (clojure.core/count %) Integer/MAX_VALUE), :val [], :via [], :in []}], :clojure.spec.test/args (), :clojure.spec.test/val [], :clojure.spec/failure :check-failed}
 :via
 [{:type clojure.lang.ExceptionInfo
   :message "Specification-based check failed"

luxbock19:10:46

thanks, yeah the function which I simplified here probably won't need a spec at all, but it's good to know this for the future

jasonjckn20:10:29

how do I specify that ::start_date must start before ::end_date in a map

jasonjckn20:10:48

so far I have (s/keys :req-un [::start-date ::end-date]) but I need to add in a predicate

jasonjckn20:10:55

the relationship between these two

jrheard20:10:54

perhaps you could write a constructor function rather than making instances of that map by hand, and it’s got an (s/fdef) that encodes that information?

jrheard20:10:53

doesn’t 100% solve the problem though

mlimotte20:10:08

maybe you could use s/and and a predicate, something like: (s/and (s/keys :req-un [::start-date ::end-date]) #( date-before? (:start-date %) (:end-date %)))

jrheard20:10:26

oh interesting

jrheard20:10:30

i like that better

jasonjckn20:10:51

cool thanks, testing now

luxbock20:10:34

what is the use case of the optional argument unf to conformer?

bfabry20:10:43

@luxbock I'm guessing it's for a custom unformer

luxbock20:10:41

ah right, yeah I get it now

bfabry20:10:14

boot.user=> (s/def ::thing (s/conformer {1 "foo"}))
:boot.user/thing
boot.user=> (s/unform ::thing (s/conform ::thing 1))

java.lang.IllegalStateException: no unform fn for conformer
boot.user=> (s/def ::thing (s/conformer {1 "foo"} {"foo" 1}))
:boot.user/thing
boot.user=> (s/unform ::thing (s/conform ::thing 1))
1

jasonjckn21:10:28

is there a way to include doc string with the spec?

jasonjckn21:10:56

e.g. (s/and (s/keys :req-un [::start-date ::end-date]) "start date must come before end date" #( date-before? (:start-date %) (:end-date %)))

jasonjckn21:10:46

(and retrieve the doc string in explain-data)

jrheard22:10:27

has anyone else had trouble doing eg

(stest/instrument (stest/enumerate-namespace ‘my.ns))
in cljs?

jrheard22:10:01

i see a stacktrace with error messages like java.lang.RuntimeException: No such namespace: stest, compiling:(/private/var/folders/zl/bh7pbyz95rg7pmcvcc_f_kdm0000gn/T/form-init2230077429322923281.clj:6:19); gonna dig into it a bit, just curious if this is known / expected / if anyone else has dealt with this

jrheard22:10:17

if i do eg

(let [syms (stest/enumerate-namespace 'voke.events)]
    (stest/instrument syms))
then i get
Caused by: clojure.lang.ExceptionInfo: java.lang.RuntimeException: Unable to resolve symbol: syms in this context
feels like i must be doing something wrong

jrheard22:10:34

@dnolen am i doing something wrong / is this known/expected?

dnolen22:10:06

@jrheard yes won’t work, not intended to work

jrheard22:10:12

cool, good to know

jrheard22:10:27

should i just instrument vars by hand, naming one at a time, or is there some better way?

dnolen22:10:36

instrument is a macro - must take symbols that reference vars directly

dnolen22:10:44

just skip the locals stuff

jrheard22:10:50

i don’t follow

dnolen22:10:00

remove the let binding and it will work

dnolen22:10:12

i.e. do this inline

jrheard22:10:19

when i do (stest/instrument (stest/enumerate-namespace 'my.ns)), i get an error message complaining that stest doesn’t exist

jrheard22:10:34

is that what you mean by doing this inline, or am i misunderstanding?

dnolen22:10:42

so that’s a bug, file an issue in JIRA

jrheard22:10:46

gotcha, will do! thanks!

dnolen22:10:06

thanks, to be clear, do this in the CLJS JIRA

jrheard22:10:08

you got it

jrheard22:10:05

( CLJS-1811 )

Oliver George23:10:45

Today's random spec experiment: Can you define an SQL schema from a clojure.spec definition?

Oliver George23:10:13

(do
  (s/def ::name string?)
  (s/def ::address (varchar 256))
  (s/def ::age integer?)
  (s/def ::gender #{"M" "F"})
  (s/def ::example-table (s/keys :req-un [::name ::age ::gender]
                                 :opt-un [::address]))

  (spec->sql-table ::example-table))

bfabry23:10:24

oooh I should bookmark this. I'm definitely going to need spec->avro schema at some point

Oliver George23:10:38

Produces

[["name" "varchar2(4000)" "not null"]
  ["age" "int" "not null"]
  ["gender" "varchar2(1)" "not null"]
  ["address" "varchar2(256)"]]