Skip to content

Instantly share code, notes, and snippets.

@realgenekim
Last active October 9, 2018 23:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save realgenekim/786b8a1447e36e91f48f901f0317e950 to your computer and use it in GitHub Desktop.
Save realgenekim/786b8a1447e36e91f48f901f0317e950 to your computer and use it in GitHub Desktop.
My starting point for ghostwheel type checking
(ns bookserver.io
#:ghostwheel.core{:trace true
:check false
:num-tests 0
; oustrument to check types at run-time for all functions
; in this namespace
:outstrument true}
(:require [clojure.spec.alpha :as s]
[ghostwheel.core :as g
:refer [>defn >defn- >fdef => | <- ?]]))
; human readable spec errors, from expound library
(set! s/*explain-out* expound.alpha/printer)
; example function
(>defn create-hiccup-table-row
" take a vector of values [0 2 2 ...], turn them into hiccup "
[row]
[vector? =>
; vector of hiccup: [:tr [:td 0] [:td 2] ...]
vector?]
(->> row
(map #(conj [:td] %))
(apply conj [:tr])))
; force tracing, overwriting ns level defaults
(>defn ^::g/trace linkify-embed-images-desc
[card]
[map? => vector?]
nil)
; @genekim Oh, `::g/trace` is just a regular metadata key like everything else and it's set to 0 by default.
; So you just have to attach it to the function like you would any other function metadata in Clojure, so
; either `(>defn ^{::g/trace 0} fn-name ...)` or `(>defn fn-name {::g/trace 0} ...}`
(>defn ^{::g/trace 0} linkify-embed-images-desc
[card]
[map? => vector?]
nil)
; super handy spec is sequential?, which accepts seqs, lists, vectors
; (s/nulable sequential?) allows nil values, too.
(>defn foo
[coll]
[(s/nllable sequential?) => sequential?)
@realgenekim
Copy link
Author

realgenekim commented Aug 13, 2018

Once you've set :outstrument true, in a REPL, you can confirm that malformed function args will generate a spec error. Using expound makes errors more human-readable, as well.

@realgenekim
Copy link
Author

realgenekim commented Sep 24, 2018

I used to do things like this, to confirm the correct types, which was super-helpful, but sometimes cumbersome to write:

(defn index-of [coll value]
  {:pre [(s/valid? coll? coll)]}
  (some (fn [[idx item]] (if (= value item) idx))
        ; [x y z] -> [[0 x] [1 y] [2 z]]
        (map-indexed vector coll)))

I find ghostwheel syntax to be much more pleasing and easier to write.

As I have to read or modify code I wrote before, I find myself adding ghostwheel-style typing information, which makes me very happy. Thank you @gnl!

@realgenekim
Copy link
Author

In Java 10, you must require [expound "0.7.1"], otherwise you'll get an exception when you (set!).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment