Skip to content

Instantly share code, notes, and snippets.

@madstap
Last active July 23, 2016 16:22
Show Gist options
  • Save madstap/e74e6599ea4399ee0591fa06e239be5c to your computer and use it in GitHub Desktop.
Save madstap/e74e6599ea4399ee0591fa06e239be5c to your computer and use it in GitHub Desktop.
(ns things.defn-spec
(:require [clojure.spec :as s]
[clojure.test :as test :refer [deftest testing is are]]
[clojure.spec.test :as stest]))
'([name doc-string? attr-map? [params*] prepost-map? body]
[name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?]) ; What's this last map for?
(defn non-&-sym? [x] (and (symbol? x) (not= '& x)))
(s/def ::destructuring-map map?) ;; TODO
(s/def ::destructuring-form
(s/or :vector ::args
:map ::destructuring-map
:symbol non-&-sym?))
(s/def ::args
(s/and vector?
(s/cat :normal-args (s/* ::destructuring-form)
:varargs (s/? (s/cat :& #{'&}
:arg ::destructuring-form)))))
(s/def ::form any?)
(s/def ::prepost (s/and vector? (s/* ::form)))
(s/def ::pre ::prepost)
(s/def ::post ::prepost)
(s/def ::prepost-map (s/keys :opt [::pre ::post]))
(s/def ::defn-body
(s/cat :args ::args
:prepost-map (s/? ::prepost-map)
:body (s/* ::form)))
(s/def ::defn
(s/cat :name symbol?
:doc-string (s/? string?)
:attr-map (s/? map?)
:body
(s/alt
:single-arity ::defn-body
:multiple-arities (s/* (s/and list? ::defn-body)))))
;; rum
(s/def ::mixin (s/or :literal map?, :var symbol?))
(s/def ::defc
(s/cat :name symbol?
:mixin-block
(s/alt
:with-mixins
(s/cat :< #{'<}
:mixins (s/* ::mixin))
:< (s/? #{'<}))
:doc-string (s/? string?)
:args ::args
:prepost-map (s/? ::prepost-map)
:body (s/* ::form)))
(deftest defn-spec-test
(testing "Validity"
(are [valid? form] (= valid? (s/valid? ::defn (rest form)))
true '(defn f [x] (* x x))
true '(defn f [])
true '(defn f "doc" [])
true '(defn f "Doc" {:style/indent 2} [a & b] (something b))
true '(defn f "docs" {:style/indent 1} [a & b] {:pre [true]} (+ a b))
true '(defn f [a] {:pre [true]})
true '(defn f "docs" {:style/indent 1} [a b & rest] (+ a b))
true '(defn f [{:keys [a b c] :as xs}] (+ a b c))
true '(defn f ([x] x) ([x & xs] xs))
true '(defn f "doc" ([x] x) ([x & xs] xs))
true '(defn f "doc" ([x] x) ([x & xs] {:pre [true]} xs))
false '(defn f (+ 1 2))
false '(defn [x] (+ x x))
false '(defn "docs" f [x]))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment