Skip to content

Commit

Permalink
Add support for speccing result vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
weavejester committed Jun 25, 2017
1 parent 50c6593 commit c366340
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 5 deletions.
19 changes: 17 additions & 2 deletions src/ataraxy/core.clj
Expand Up @@ -102,6 +102,16 @@
{:pre [(valid? routes)]}
(parse-routing-table {} (s/conform ::routing-table-with-meta routes)))

(defmulti result-spec
"Return the spec for a result vector. Dispatches off the first element of the
vector (the 'key'). Used to spec out :ataraxy/result."
first)

(defmethod result-spec :default [_] any?)

(s/def :ataraxy/result
(s/and vector? (s/multi-spec result-spec first)))

(defn- optional-binding? [sym]
(str/starts-with? (name sym) "?"))

Expand All @@ -115,10 +125,15 @@
`(-> #{} ~@(for [sym symbols] `(cond-> (not ~sym) (conj '~sym)))))

(defn- compile-match-result [{:keys [key args]} meta coercers result-form]
(let [coercions (into {} (keep (partial compile-coercion coercers) args))]
(let [coercions (into {} (keep (partial compile-coercion coercers) args))
result (gensym "result")
failure (gensym "failure")]
`(let [~@(apply concat coercions)]
(if (and ~@(remove optional-binding? (keys coercions)))
~(result-form (into [key] args))
(let [~result [~key ~@args]]
(if-let [~failure (s/explain-data :ataraxy/result ~result)]
~(result-form [::err/failed-spec failure])
~(result-form result)))
~(result-form [::err/failed-coercions (missing-symbol-set args)])))))

(defn- param-name [sym]
Expand Down
6 changes: 5 additions & 1 deletion src/ataraxy/error.clj
Expand Up @@ -10,7 +10,8 @@
::unmatched-method 1
::missing-params 2
::missing-destruct 3
::failed-coercions 4})
::failed-coercions 4
::failed-spec 5})

(defn error-result?
"Return true if the result is an Ataraxy error result."
Expand All @@ -31,3 +32,6 @@

(defmethod handler/sync-default ::failed-coercions [_]
[::response/bad-request "Bad Request"])

(defmethod handler/sync-default ::failed-spec [_]
[::response/bad-request "Bad Request"])
24 changes: 22 additions & 2 deletions test/ataraxy/core_test.clj
@@ -1,10 +1,14 @@
(ns ataraxy.core-test
(:require [clojure.test :refer :all]
(:require [clojure.spec.alpha :as s]
[clojure.test :refer :all]
[ataraxy.core :as ataraxy]
[ataraxy.error :as err]
[ataraxy.response :as response]
[clojure.java.io :as io]))

(defmethod ataraxy/result-spec ::foo [_]
(s/cat :key keyword? :id (s/and int? #(> % 10))))

(deftest test-valid?
(are [x y] (= (ataraxy/valid? x) y)
'{"/foo" [:bar]} true
Expand Down Expand Up @@ -141,7 +145,23 @@
{:request-method :put, :uri "/foo/10"} [::err/unmatched-method]
{:request-method :get, :uri "/foo/10"} [::err/missing-params '#{page}]
{:request-method :get, :uri "/foo/10"
:query-params {"page" "x"}} [::err/failed-coercions '#{page}]))))
:query-params {"page" "x"}} [::err/failed-coercions '#{page}])))

(testing "specs"
(let [routes '{[:get "/foo/" id] [::foo ^int id]}]
(are [req res] (= (ataraxy/matches routes req) res)
{:request-method :get, :uri "/foo/20"} [::foo 20]
{:request-method :get, :uri "/foo/10"}
[::err/failed-spec
'#:clojure.spec.alpha{:problems
[{:path [:ataraxy.core-test/foo :id],
:pred
(clojure.core/fn [%] (clojure.core/> % 10)),
:val 10,
:via [:ataraxy/result],
:in [1]}],
:spec :ataraxy/result,
:value [:ataraxy.core-test/foo 10]}]))))

(deftest test-handler
(testing "synchronous handler"
Expand Down

0 comments on commit c366340

Please sign in to comment.