(str (js/Date.))
              
	    

Open this presentation in your computer for a collaborative live coding session: http://slides.klipse.tech/clojure-spec-cr17/part1.html#slide-3
(It works also on mobile)
The interactive code snippets are powered by KLIPSE. 🤗
	    (map inc [1 2 3])
	 
      Most significant part of Clojure 1.9.
 clojure.spec features: 
 All you have to do is to require clojure.spec like this:
	      (ns foo.core
	      (:require [clojure.spec.alpha :as s]))
	   
	
	    (s/def ::id integer?)
	    (s/def ::name string?)
	
	Any predicate can be passed to the spec definition:
(A predicate is a function that returns a boolean)
	      (s/def ::my-big-integer (fn [x] (and (integer? x)
	      (> x 1000000))))
	  
	  
	      (s/def ::my-short-string (fn [x] (and (string? x)
	      (< (count x) 5))))
		 
	
	  Pay attention to the ::! 
	  Spec definitions must used namespace keywords
	
	    (s/def :a-big-integer (fn [x] (and (integer? x)
	    (> x 1000000))))
	  
	  
	  Namespaced keywords are like keywords but they are namespaced
The double colon is a syntactic sugar for the current namespace:
		::hello
	    
	    
	     Mandatory in clojure.spec because specs are registered in a global registry!
Validate data with spec
	    (s/valid? ::id 19)
	
	
	    (s/valid? ::id "my-id")
	
	
	And with one of our custom predicates:
	      (s/valid? ::my-big-integer "abc")
	  
	  
	      (s/valid? ::my-big-integer 17)
	  
	  Wouldn't it be great if we could get an explanation about what parts of the spec were not satisfied?
Explain validation
	    (s/explain-str ::my-big-integer "abc")
	
        Not so useful 😕
Big Integer - the real way
            (s/def ::big-integer (s/and integer?
            #(> % 1000000)))
	
	When it's not an integer:
	      (s/explain-str ::big-integer "abc")
	  
	  When it's a small integer:
	      (s/explain-str ::big-integer 42)
	  
	  Much better 😄
Short String - the real way
              (s/def ::short-string (s/and string?
              #(< (count %) 5)))
		  
	  When it's not a string:
	      (s/explain-str ::short-string 42)
	  
	  When it's a long string:
	      (s/explain-str ::short-string "Hello World!")
	  
	We must annotate each branch with a tag
	    (s/def ::big-integer-or-short-string (s/or :int ::big-integer
	    :str ::short-string))
	
	That makes the explanations about the failure really clear:
            (s/explain-str ::big-integer-or-short-string :hello-world!)
	
      Conform is a fancy term for data parsing according to a spec
With primitives, the conformed data is the same as the original data
(s/conform ::id 4200000)
	  
	  With non-primitives, the conformed data is parsed into a data structure with information about the data
When it's a big integer:
              (s/conform ::big-integer-or-short-string 4200000)
	  
	  When it's a small string:
              (s/conform ::big-integer-or-short-string "abc")
	  
	  When it's neither this nor that:
              (s/conform ::big-integer-or-short-string :hello-world!)
	  
	  It works well with a nested spec
	      (s/def ::my-special-spec (s/or :keyword keyword?
	      :bioss ::big-integer-or-short-string))
              (s/conform ::my-special-spec "aa")
	  
	 You describe the structure of your maps by combining the specs of its keys 
 and specifying what keys are required and what keys are optional 
	      (s/def ::my-map (s/keys :req [::big-integer]
              :opt [::short-string]))
	  
	This one is valid:
	      (s/explain-str ::my-map {::big-integer 90000000
              ::short-string "Hell"})
	  
	  This one is invalid for 2 reasons:
	      (s/explain-str ::my-map {::big-integer 90
              ::short-string "Hello World!"})
	  
	What about this one?
	      (s/valid? (s/keys) {::big-integer-or-short-string 90})
	  
	It's a bit surprising but in spec, ALL the namespace-qualified keys are validated by any registered specs!
Why do we need opt?
You can also have unspaced keywords
	      (s/def ::my-map-un (s/keys :req-un [::big-integer]
              :opt-un [::short-string]))
	  
	  This one is valid:
	      (s/explain-str ::my-map-un {:big-integer 90000000
              :short-string "Hell"})
	  
	  This one is invalid for 2 reasons:
	      (s/explain-str ::my-map-un {:big-integer 90
              :short-string "Hello World!"})
	  
	What about this one?
	      (s/valid? (s/keys) {:big-integer-or-short-string 90})
	  
	Only the namespace-qualified keys are validated by any registered specs!
You can desribe the shape of a data sequence using Regular Expressions operators:
An example:
	      (s/def ::employee (s/cat :name (s/alt :full string?
              :first-and-last (s/tuple string? string?))
              :salary ::big-integer))
	  
	
	      (s/explain-str ::employee '("John Woo" 999))
	  
	  
	      (s/conform ::employee '(["John" "Woo"] 9999999))
	  
	You can describe the shape of a data sequence using Regular Expressions operators:
 A simplified version of the args of defn: 
	      (s/def ::defn-args (s/cat :name symbol?
              :docstring (s/? string?)
              :args (s/coll-of symbol? :kind vector?)))
	  
	   With a doc string : (defn foo "foo receives two arguments" [a b])
		(s/conform ::defn-args ['foo "foo receives two arguments" '[a b]])
	    
	     Without a doc string : (defn foo [a b c d])
		(s/conform ::defn-args ['foo '[a b c d]])
	    
	   A simplified version of the args of fn: 
(It's not exactly a collection of symbols)
	      (s/def ::good-symbol #(and (symbol? %) (not= % '&)))
	      (s/def ::fn-args (s/and vector?
              (s/cat :args (s/* ::good-symbol)
              :rest (s/? (s/cat :& '#{&}
              :other ::good-symbol)))))
	  
	
	      (s/conform ::fn-args '[a b & c])
	  
	s/alt vs. s/or  Usually inside the spec of a sequence, we use s/alt:
	
(s/def ::seq-alt (s/cat :str string?
                  :numbers-alt-string (s/alt :nums (s/* number?)
                                             :strs (s/* string?))))
(s/conform ::seq-alt ["hello" 1 2 3])
	
 When we need part of the sequence to be nested, we use s/or:
	
(s/def ::seq-or (s/cat :str string?
                  :numbers-or-string (s/or :nums (s/* number?) 
                                           :strs (s/* string?))))
(s/conform ::seq-or ["hello" [1 2 3]])
	
You can describe a spec
	    (s/describe ::fn-args)
	
      What have we learned?

	powered by KLIPSE /