Как мне сделать собственный генератор clojure.spec?

Я пытаюсь специфицировать следующую структуру данных под названием Connection:

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

Вот моя спецификация:

(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)

Я получаю следующую ошибку, и я понятия не имею, что здесь не так:

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}

1 ответ

Решение

Я не могу воспроизвести вашу ошибку, но хотел бы отметить пару вещей, которые могут помочь вам в этом.

Ваш gen/fmap игнорировать его параметр вещь уже вещь: gen/return,

Здесь вы вызываете ключевое слово без аргументов, это вызовет IllegalArgumentException, Просто удалите паренсы вокруг ::channel-type,

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

И здесь вы делаете спецификацию args, которая говорит об одной вещи. :args всегда последовательность аргументов, если функция принимает только один аргумент, это последовательность длины один. Вы обычно используете s/cat,

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

Следующее работает для меня. (Предполагается, что материал вашего канала правильный.)

(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] ,,,)

  )
Другие вопросы по тегам