Skip to content

Instantly share code, notes, and snippets.

@danielneal
Last active October 26, 2017 14:03
Show Gist options
  • Save danielneal/d82c142c9eab9f8caec0fa93b87ff7f3 to your computer and use it in GitHub Desktop.
Save danielneal/d82c142c9eab9f8caec0fa93b87ff7f3 to your computer and use it in GitHub Desktop.
(ns stupidsense.core
(:require [clojure.spec.alpha :as s]
[clojure.string :as str]
[clojure.core.specs.alpha]))
(def blacklist-ns #{"clojure.core"})
(defn fn-specs [registry]
(into {} (for [[sym spec] registry
:let [form (s/form spec)]
:when (and (not (contains? blacklist-ns (namespace sym)))
(seqable? form)
(= (first form) 'clojure.spec.alpha/fspec))]
[sym form])))
(s/def
::fn-spec
(s/cat :fspec- #{'clojure.spec.alpha/fspec}
:args- #{:args}
:args (s/spec (s/cat :cat- #{'clojure.spec.alpha/cat}
:args (s/* (s/cat :arg keyword? :spec any?))))
:ret- #{:ret}
:ret any?
:fn- #{:fn}
:fn any?))
(def arg-spec
(s/spec (eval (-> (s/conform ::fn-spec (s/form a-spec))
:args
:args
first
:spec))))
(defn arg-specs
[fn-spec]
(let [conformed (s/conform ::fn-spec fn-spec)
args (get-in conformed [:args :args])]
(for [{:keys [arg spec]} args]
[arg {:spec-form spec
:spec (s/spec (eval spec))}])))
(defn format-option [fn-name substitute-arg arg-specs value]
(apply list fn-name (for [[arg {:keys [spec spec-form]}] arg-specs]
(if (= arg substitute-arg)
value
(symbol (str "?" (name arg)))))))
(defn applicable [registry value]
(let [fn-specs (fn-specs registry)]
(for [[fn-name fn-spec] fn-specs
:let [arg-specs (arg-specs fn-spec)]
arg-spec arg-specs
:let [[arg {:keys [spec spec-form]}] arg-spec]
:when (s/valid? spec value)]
(format-option fn-name arg arg-specs value))))
(s/fdef make-bigger
:args (s/cat :x int?)
:ret int?)
(defn make-bigger [number]
(inc number))
(s/def ::first-name string?)
(s/fdef make-greeting
:args (s/cat :person (s/keys :req-un [::first-name]))
:ret string?)
(defn make-greeting [person]
(str "Hello, " (get person :first-name)))
(s/fdef square-root
:args (s/cat :num (s/and number? pos?))
:ret map?)
(defn square-root [num]
(Math/sqrt num))
(s/fdef d
:args (s/cat :d (s/and number? #(> % 5)))
:ret map?)
(s/fdef add
:args (s/cat :a number? :b number?)
:ret number?)
(defn add [a b]
(+ a b))
(defn huge-number? [num]
(> num 100000))
(s/fdef huge-number?
:args (s/cat :num number? )
:ret boolean?)
;; WILD DEMO
(applicable (s/registry) 3)
;; ((stupidsense.core/make-bigger 3)
;; (stupidsense.core/square-root 3)
;; (stupidsense.core/huge-number? 3)
;; (stupidsense.core/add 3 ?b)
;; (stupidsense.core/add ?a 3))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment