简体   繁体   English

如何制作自定义clojure.spec生成器?

[英]How do I make custom clojure.spec generator?

I'm trying to spec the following data structure called Connection: 我正在尝试指定以下称为Connection的数据结构:

{:id "some string" :channel "instance of org.httpkit.server.AsyncChannel" }

Here is my spec: 这是我的规格:

(defn make-channel []
  (proxy [AsyncChannel] [nil nil]
    (toString [] "mock AsyncChannel")))

(defn channel-gen
  []
  (->> (s/gen (s/int-in 0 1))
       (gen/fmap (fn [_] (make-channel)))))

(s/def ::channel (s/spec (::channel-type)
                         :gen channel-gen))

(s/def ::id string?)

(s/def ::connection (s/keys :req-un [::channel ::id]))

(s/fdef make-connection
        :args ::channel
        :ret ::connection)

I'm getting the following error and I have no clue what is wrong here: 我收到以下错误,我不知道这里出了什么问题:

clojure.lang.ExceptionInfo: Unable to construct gen at: [] for: gameserve.ws$make_connection@788ffa19
clojure.lang.Compiler$CompilerException: clojure.lang.ExceptionInfo: Unable to construct gen at: [] for: gameserve.ws$make_connection@788ffa19 #:clojure.spec.alpha{:path [], :form #object[gameserve.ws$make_connection 0x788ffa19 "gameserve.ws$make_connection@788ffa19"], :failure :no-gen}

I can't reproduce your error, but wanted to point out a couple of things that might help you get this working. 我无法重现您的错误,但想指出一些可能有助于您解决此问题的方法。

Your gen/fmap ignoring its parameter thing is already a thing: gen/return . 您的gen/fmap忽略其参数事物已经是一件事情: gen/return

Here you're calling a keyword with no arguments, this will throw an IllegalArgumentException . 在这里,您要调用不带参数的关键字,这将引发IllegalArgumentException Just remove the parens around ::channel-type . 只需删除::channel-type周围的括号即可。

(s/def ::channel (s/spec (::channel-type)
                         :gen channel-gen))

And here you're making an args spec that talks about a single thing. 在这里,您正在制定一个讨论单个问题的args规范。 :args is always a sequence of arguments, if the function takes only one argument, it's a sequence of length one. :args始终是一个参数序列,如果函数仅接受一个参数,则其长度为一。 You'd normally use s/cat . 您通常会使用s/cat

(s/fdef make-connection
  :args ::channel
  :ret ::connection)

The following works for me. 以下对我有用。 (It assumes that your channel stuff is correct.) (假设您的频道内容正确。)

(ns foo.core
  (:require
   [clojure.spec.gen.alpha :as gen]
   [clojure.spec.alpha :as s]))

(defn make-channel []
  :mock-channel)

(defn channel-gen
  []
  (gen/return (make-channel)))

(s/def ::channel-type any?)

(s/def ::channel (s/spec ::channel-type
                         :gen channel-gen))

(s/def ::id string?)

(s/def ::connection (s/keys :req-un [::channel ::id]))

(defn make-connection [c])

(s/fdef make-connection
  :args (s/cat :c ::channel)
  :ret ::connection)

(comment

  (s/exercise ::connection)
  ;;=> ([{:channel :mock-channel, :id ""} {:channel :mock-channel, :id ""}]
  ;;    [{:channel :mock-channel, :id "k"} {:channel :mock-channel, :id "k"}] ,,,)

  (s/exercise-fn `make-connection)
  ;;=> ([(:mock-channel) nil] [(:mock-channel) nil] ,,,)

  )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM