Markus Agwin / Dec 04 2018

Re-using spec definitions (via patched s/conform)

1.
Introduction

I want clojure.spec.alpha to process my data with spec definitions written by colleagues. This involves patching Clojure. As a data scientist, I do not care so much about the risk of breaking backward compatibility. That is because I do not take my code "in production" in the sense that a software company would do. I want to quick-and-dirty crunch numbers with minimum own code, re-using everything that is out there.

2.
Trying to re-use spec definitions

Some preparation

{:deps 
 {org.clojure/clojure {:mvn/version "1.10.0-beta8"}}}
deps.edn
Extensible Data Notation
(require '[clojure.spec.alpha :as s])

Fellow Bob gave me this well conceived spec definitions...

(s/def ::age integer?)
(s/def ::sample (s/keys :req-un [::age]))

...and it works for his data sample

(def bob-sample {:age 12})
(s/conform ::sample bob-sample)

My own data sample invalidates Bob's specs

(s/conform ::sample {:age "12Y"})

I want clojure.spec.alpha to process my data with Bob's specs. So I patch Clojure.

3.
Patching Clojure

...Hier kommt die Patch Magic...

4.
Successfully re-using Bob's specs

Finally I reach my goal. Importing the patched spec.alpha library, ...

{:deps
 {org.clojure/clojure
   {:mvn/version "1.10.0-beta8"}
  org.clojure/spec.alpha
  {:local/root "spec.alpha-0.1.143-SNAPSHOT.jar"}}}
deps.edn
Extensible Data Notation

... I can re-use Bob's specs via the enhanced syntax of the patched s/conform function

(defn string->int-conforming
  [spec]
  (condp = spec
    ::sample
    (fn [_ x _]
      (let [y (:age x)]
        (cond
          (s/valid? ::sample x)  x
          (string? y) (try
                        {:age (Long/parseLong (subs y 0 (dec (count y))))}
                        (catch Exception _
                          ::s/invalid))
          :else ::s/invalid)))
    nil))

(s/conform ::sample {:age "12Y"} string->int-conforming)

Of course, Bob's data still works.

(s/conform ::sample bob-sample string->int-conforming)

5.
Proposal for easier use of patches

A typical data scientist is not able to use git and maven. Hence he cannot unleash the power of the quick-and-dirty patches of the Clojure community. It would be of great help if I, instead of following all the steps of the "Patching Clojure" section, could simply write the following deps.edn file:

{:deps
 {org.clojure/clojure
   {:mvn/version "1.10.0-beta8"}
  org.clojure/spec.alpha
  {:mvn/version "0.1.143"
	 :patch "https://dev.clojure.org/jira/secure/attachment/17111/clj-2116.patch"}}}
Julia