core general functions

Author: Chris Zheng  (z@caudate.me)
Date: 27 November 2018
Repository: https://github.com/zcaudate/hara
Version: 3.0.2

1    Introduction

1.1    Installation

Add to project.clj dependencies:

[hara/base "3.0.2"]

2    Check



agent? ^

returns `true` if `x` is of type `clojure.lang.Agent`.

v 3.0
(defn agent?
  [obj]
  (instance? clojure.lang.Agent obj))
link
(agent? (agent nil)) => true

atom? ^

returns `true` if `x` is of type `clojure.lang.Atom`.

v 3.0
(defn atom?
  [obj]
  (instance? clojure.lang.Atom obj))
link
(atom? (atom nil)) => true

bigdec? ^

returns `true` if `x` is of type `java.math.BigDecimal`.

v 3.0
(defn bigdec?
  [x] (instance? java.math.BigDecimal x))
link
(bigdec? 1M) => true (bigdec? 1.0) => false

bigint? ^

returns `true` if `x` is of type `clojure.lang.BigInt`.

v 3.0
(defn bigint?
  [x] (instance? clojure.lang.BigInt x))
link
(bigint? 1N) => true (bigint? 1) => false

boolean? ^

returns `true` if `x` is of type `java.lang.Boolean`.

v 3.0
(defn boolean?
  [x] (instance? java.lang.Boolean x))
link
(boolean? true) => true (boolean? false) => true

byte? ^

returns `true` if `x` is of type `java.lang.Byte`

v 3.0
(defn byte?
  [x] (instance? java.lang.Byte x))
link
(byte? (byte 1)) => true

bytes? ^

returns `true` if `x` is a primitive `byte` array.

v 3.0
(defn bytes?
  [^Object x]
  (= (Class/forName "[B")
     (.getClass x)))
link
(bytes? (byte-array 8)) => true

comparable? ^

returns `true` if `x` and `y` both implements `java.lang.Comparable`.

v 3.0
(defn comparable?
  [x y]
  (and (instance? Comparable x)
       (instance? Comparable y)
       (= (type x) (type y))))
link
(comparable? 1 1) => true

double? ^

returns `true` if `x` is of type `java.lang.Double`.

v 3.0
(defn double?
  [x] (instance? java.lang.Double x))
link
(double? 1) => false (double? (double 1)) => true

edn? ^

checks if an entry is valid edn

v 3.0
(defn edn?
  [x]
  (or (nil? x)
      (boolean? x)
      (string? x)
      (char? x)
      (symbol? x)
      (keyword? x)
      (number? x)
      (seq? x)
      (vector? x)
      (record? x)
      (map? x)
      (set? x)
      (tagged-literal? x)
      (var? x)
      (regexp? x)))
link
(edn? 1) => true (edn? {}) => true (edn? (java.util.Date.)) => false

hash-map? ^

returns `true` if `x` implements `clojure.lang.APersistentMap`.

v 3.0
(defn hash-map?
  [x] (instance? clojure.lang.APersistentMap x))
link
(hash-map? {}) => true (hash-map? []) => false

ideref? ^

returns `true` if `x` is of type `java.lang.IDeref`.

v 3.0
(defn ideref?
  [obj]
  (instance? clojure.lang.IDeref obj))
link
(ideref? (atom 0)) => true (ideref? (promise)) => true (ideref? (future)) => true

instant? ^

returns `true` if `x` is of type `java.util.Date`.

v 3.0
(defn instant?
  [x] (instance? java.util.Date x))
link
(instant? (java.util.Date.)) => true

iobj? ^

checks if a component is instance of clojure.lang.IObj

v 3.0
(defn iobj?
  [x]
  (instance? clojure.lang.IObj x))
link
(iobj? 1) => false (iobj? {}) => true

iref? ^

returns `true` if `x` is of type `clojure.lang.IRef`.

v 3.0
(defn iref?
  [obj]
  (instance? clojure.lang.IRef obj))
link
(iref? (atom 0)) => true (iref? (ref 0)) => true (iref? (agent 0)) => true (iref? (promise)) => false (iref? (future)) => false

lazy-seq? ^

returns `true` if `x` implements `clojure.lang.LazySeq`.

v 3.0
(defn lazy-seq?
  [x] (instance? clojure.lang.LazySeq x))
link
(lazy-seq? (map inc [1 2 3])) => true (lazy-seq? ()) => false

long? ^

returns `true` if `x` is of type `java.lang.Long`.

v 3.0
(defn long?
  [x] (instance? java.lang.Long x))
link
(long? 1) => true (long? 1N) => false

promise? ^

returns `true` is `x` is a promise

v 3.0
(defn promise?
  [^Object obj]
  (let [^String s (.getName ^Class (type obj))]
    (.startsWith s "clojure.core$promise$")))
link
(promise? (promise)) => true (promise? (future)) => false

ref? ^

returns `true` if `x` is of type `clojure.lang.Ref`.

v 3.0
(defn ref?
  [obj]
  (instance? clojure.lang.Ref obj))
link
(ref? (ref nil)) => true

regexp? ^

returns `true` if `x` implements `clojure.lang.IPersistentMap`.

v 3.0
(defn regexp?
  [x] (instance? java.util.regex.Pattern x))
link
(regexp? #"d+") => true

short? ^

returns `true` if `x` is of type `java.lang.Short`

v 3.0
(defn short?
  [x] (instance? java.lang.Short x))
link
(short? (short 1)) => true

thread? ^

returns `true` is `x` is a thread

v 3.0
(defn thread?
  [obj]
  (instance? java.lang.Thread obj))
link
(thread? (Thread/currentThread)) => true

type-checker ^

returns the checking function associated with `k`

v 3.0
(defn type-checker
  [k]
  (resolve (symbol (str (name k) "?"))))
link
(type-checker :string) => #'clojure.core/string? (require '[hara.core.base.check :refer [bytes?]]) (type-checker :bytes) => #'hara.core.base.check/bytes?

uri? ^

returns `true` if `x` is of type `java.net.URI`.

v 3.0
(defn uri?
  [x] (instance? java.net.URI x))
link
(uri? (java.net.URI. "http://www.google.com")) => true

url? ^

returns `true` if `x` is of type `java.net.URL`.

v 3.0
(defn url?
  [x] (instance? java.net.URL x))
link
(url? (java.net.URL. "file:/Users/chris/Development")) => true

uuid? ^

returns `true` if `x` is of type `java.util.UUID`.

v 3.0
(defn uuid?
  [x] (instance? java.util.UUID x))
link
(uuid? (java.util.UUID/randomUUID)) => true

3    Class



abstract? ^

returns `true` if `class` is an abstract class

v 3.0
(defn abstract?
  [^java.lang.Class class]
  (java.lang.reflect.Modifier/isAbstract (.getModifiers class)))
link
(abstract? java.util.Map) => true (abstract? Class) => false

array-component ^

returns the array element within the array

v 3.0
(defn array-component
  [cls]
  (if (array? cls)
    (.getComponentType cls)
    (throw (ex-info "Not an array" {:class cls}))))
link
(array-component (type (int-array 0))) => Integer/TYPE (array-component (type (into-array [1 2 3]))) => java.lang.Long

array? ^

checks if a class is an array class

v 3.0
(defn array?
  [cls]
  (.isArray cls))
link
(array? (type (int-array 0))) => true

interface? ^

returns `true` if `class` is an interface

v 3.0
(defn interface?
  [^java.lang.Class class]
  (.isInterface class))
link
(interface? java.util.Map) => true (interface? Class) => false

primitive-array? ^

checks if class is a primitive array

v 3.0
(defn primitive-array?
  [cls]
  (and (.isArray cls)
       (.isPrimitive (.getComponentType cls))))
link
(primitive-array? (type (int-array 0))) => true (primitive-array? (type (into-array [1 2 3]))) => false

4    Encode



from-base64 ^

turns a base64 encoded string into a byte array

v 3.0
(defn from-base64
  [input]
  (.decode (Base64/getDecoder)
           input))
link
(-> (from-base64 "aGVsbG8=") (String.)) => "hello"

from-hex ^

turns a hex string into a sequence of bytes

v 3.0
(defn from-hex
  [s]
  (byte-array (map #(apply from-hex-chars %) (partition 2 s))))
link
(String. (from-hex "68656c6c6f")) => "hello"

from-hex-chars ^

turns two hex characters into a byte value

v 3.0
(defn from-hex-chars
  [c1 c2]
  (unchecked-byte
   (+ (bit-shift-left (Character/digit c1 16) 4)
      (Character/digit c2 16))))
link
(byte (from-hex-chars 2 a)) => 42

hex-chars ^

turns a byte into two chars

v 3.0
(defn hex-chars
  [b]
  (let [v (bit-and b 0xFF)]
    [(+hex-array+ (bit-shift-right v 4))
     (+hex-array+ (bit-and v 0x0F))]))
link
(hex-chars 255) => [f f] (hex-chars 42) => [2 a]

to-base64 ^

turns a byte array into a base64 encoded string

v 3.0
(defn to-base64
  [bytes]
  (.encodeToString (Base64/getEncoder)
                   bytes))
link
(-> (.getBytes "hello") (to-base64)) => "aGVsbG8="

to-base64-bytes ^

turns a byte array into a base64 encoding

v 3.0
(defn to-base64-bytes
  [bytes]
  (.encode (Base64/getEncoder)
           bytes))
link
(-> (.getBytes "hello") (to-base64-bytes) (String.)) => "aGVsbG8="

to-hex ^

turns a byte array into hex string

v 3.0
(defn to-hex
  [bytes]
  (String. (to-hex-chars bytes)))
link
(to-hex (.getBytes "hello")) => "68656c6c6f"

to-hex-chars ^

turns a byte array into a hex char array

v 3.0
(defn to-hex-chars
  [bytes]
  (char-array (mapcat hex-chars bytes)))
example not found

5    Enum



create-enum ^

creates an enum value from a string

v 3.0
(defn create-enum
  [s type]
  (loop [[e :as values] (enum-values type)]
    (cond (empty? values)
          (throw (ex-info "Cannot create enum" {:type type
                                                :value s}))
          (= (str e) s) e

          :else
          (recur (rest values)))))
link
(create-enum "TYPE" ElementType) => ElementType/TYPE

enum-map ^

cached map of enum values

v 3.0
(definvoke enum-map
  [:memoize]
  ([type]
   (->> (enum-values type)
        (map (juxt (comp keyword string/spear-case string/to-string)
                   identity))
        (into {}))))
link
(enum-map ElementType)

enum-values ^

returns all values of an enum type

v 3.0
(defn enum-values
  [type]
  (let [method (.getMethod type "values" (make-array Class 0))
        values (.invoke method nil (object-array []))]
    (seq values)))
link
(->> (enum-values ElementType) (map str)) => (contains ["TYPE" "FIELD" "METHOD" "PARAMETER" "CONSTRUCTOR"] :in-any-order :gaps-ok)

enum? ^

check to see if class is an enum type

v 3.0
(defn enum?
  [type]
  (if (-> (inheritance/ancestor-list type)
          (set)
          (get java.lang.Enum))
    true false))
link
(enum? java.lang.annotation.ElementType) => true (enum? String) => false

to-enum ^

gets an enum value given a symbol

v 3.0
(defn to-enum
  [s type]
  (let [key ((comp keyword string/spear-case string/to-string) s)]
    (or (get (enum-map type) key)
        (throw (ex-info "Cannot find the enum value."
                        {:input s
                         :key key
                         :type type
                         :options (keys (enum-map type))})))))
link
(to-enum "TYPE" ElementType) => ElementType/TYPE (to-enum :field ElementType) => ElementType/FIELD

6    Error



suppress ^

suppresses any errors thrown in the body.

v 3.0
(defmacro suppress
  ([body]
   `(try ~body (catch Throwable ~'t)))
  ([body catch-val]
   `(try ~body (catch Throwable ~'t
                 (cond (fn? ~catch-val)
                       (~catch-val ~'t)
                       :else ~catch-val)))))
link
(suppress (throw (ex-info "Error" {}))) => nil (suppress (throw (ex-info "Error" {})) :error) => :error (suppress (throw (ex-info "Error" {})) (fn [e] (.getMessage e))) => "Error"

7    Inheritance



all-ancestors ^

returns all ancestors for a given type, itself included

v 3.0
(defn all-ancestors
  [cls]
  (let [bases (ancestor-list cls)
        interfaces (mapcat all-interfaces bases)]
    (set (concat bases interfaces))))
link
(all-ancestors String) => #{java.lang.CharSequence java.io.Serializable java.lang.Object java.lang.String java.lang.Comparable}

all-interfaces ^

lists all interfaces for a class

v 3.0
(defn all-interfaces
  [cls]
  (let [directs (.getInterfaces cls)
        sub (mapcat all-interfaces directs)]
    (set (concat directs sub))))
link
(all-interfaces clojure.lang.AFn) => #{java.lang.Runnable java.util.concurrent.Callable clojure.lang.IFn}

ancestor-list ^

lists the direct ancestors of a class

v 3.0
(defn ancestor-list
  ([cls] (ancestor-list cls []))
  ([^java.lang.Class cls output]
   (if (nil? cls)
     output
     (recur (.getSuperclass cls) (conj output cls)))))
link
(ancestor-list clojure.lang.PersistentHashMap) => [clojure.lang.PersistentHashMap clojure.lang.APersistentMap clojure.lang.AFn java.lang.Object]

ancestor-tree ^

lists the hierarchy of bases and interfaces of a class.

v 3.0
(defn ancestor-tree
  ([cls] (ancestor-tree cls []))
  ([^Class cls output]
   (let [base (.getSuperclass cls)]
     (if-not base output
             (recur base
                    (conj output [base (all-interfaces cls)]))))))
link
(ancestor-tree Class) => [[java.lang.Object #{java.io.Serializable java.lang.reflect.Type java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration}]]

best-match ^

finds the best matching interface or class from a list of candidates

v 3.0
(defn best-match
  [candidates ^Class cls]
  (or (get candidates cls)
      (->> (apply concat (ancestor-tree cls))
           (map (fn [v]
                  (if (set? v)
                    (first (set/intersection v candidates))
                    (get candidates v))))
           (filter identity)
           first)))
link
(best-match #{Object} Long) => Object (best-match #{String} Long) => nil (best-match #{Object Number} Long) => Number

inherits? ^

checks if one class inherits from another

v 3.0
(defn inherits?
  [ancestor cls]
  (contains? (all-ancestors cls) ancestor))
link
(inherits? clojure.lang.ILookup clojure.lang.APersistentMap) => true

8    Match



actual-pattern ^

constructs a pattern used for direct comparison

v 3.0
(defn actual-pattern
  [expression]
  (ActualPattern. expression))
link
(actual-pattern '_) (actual-pattern #{1 2 3})

actual-pattern? ^

checks if input is an actual pattern

v 3.0
(defn actual-pattern?
  ([pattern]
   (instance? ActualPattern pattern))
  ([pattern expression]
   (and (actual-pattern? pattern)
        (= expression (:expression pattern)))))
link
(actual-pattern? '_) => false (-> (actual-pattern '_) actual-pattern?) => true

eval-pattern ^

constructs a pattern that is evaluated before comparison

v 3.0
(defn eval-pattern
  [expression]
  (EvaluationPattern. expression))
link
(eval-pattern '(keyword "a")) (eval-pattern 'symbol?)

eval-pattern? ^

checks if input is an eval pattern

v 3.0
(defn eval-pattern?
  ([pattern]
   (instance? EvaluationPattern pattern))
  ([pattern expression]
   (and (eval-pattern? pattern)
        (= expression (:expression pattern)))))
link
(-> (eval-pattern 'symbol?) eval-pattern?) => true

match-inner ^

matches the inner contents of a array

v 3.0
(defn match-inner
  [template arr]
  (loop [[t & tmore :as tall] template
         [x & more :as all] arr]
    (cond (and (empty? tall) (empty? all))
          true

          (empty? tall) false

          (= t '&)
          (protocol.match/-match (first tmore) (cons x more))

          (protocol.match/-match t x)
          (recur tmore more)

          :else false)))
link
(match-inner [number? {:a {:b #'symbol?}} '& '_] [1 {:a {:b 'o}} 5 67 89 100]) => true

9    Primitive



create-lookup ^

creates a path lookup given a record

v 3.0
(defn create-lookup
  ([m] (create-lookup m util/F))
  ([m ignore]
   (reduce-kv (fn [out type record]
                (reduce-kv (fn [out k v]
                                  (if (ignore k)
                                    out
                                    (assoc out v [type k])))
                                out
                                record))
              {}
              m)))
link
(create-lookup {:byte {:name "byte" :size 1} :long {:name "long" :size 4}}) => {"byte" [:byte :name] 1 [:byte :size] "long" [:long :name] 4 [:long :size]}

primitive-type ^

converts primitive values across their different representations. The choices are: :raw - The string in the jdk (i.e. `Z` for Boolean, `C` for Character) :symbol - The symbol that hara.object.query uses for matching (i.e. boolean, char, int) :string - The string that hara.object.query uses for matching :class - The primitive class representation of the primitive :container - The containing class representation for the primitive type

v 3.0
(defn primitive-type
  ([v to]
   (if-let [[type rep] (get +primitive-lookup+ v)]
     (get-in +primitive-records+ [type to]))))
link
(primitive-type Boolean/TYPE :symbol) => 'boolean (primitive-type "Z" :symbol) => 'boolean (primitive-type "int" :symbol) => 'int (primitive-type Character :string) => "char" (primitive-type "V" :class) => Void/TYPE (primitive-type 'long :container) => Long (primitive-type 'long :type) => :long

10    Protocol



implements? ^

checks whether a type has implemented a protocol

v 3.0
(defn implements?
  ([{:keys [impls] :as protocol} type]
   (boolean (or (get impls type)
                (inheritance/inherits? (protocol-interface protocol)
                                       type)
                (map first impls)
                (filter #(inheritance/inherits? % type))
                seq)))
  ([protocol type method]
   (let [method (keyword (str method))
         impls (:impls protocol)]
     (boolean (or (get-in impls [type method])
                  (inheritance/inherits? (protocol-interface protocol)
                                         type)
                  (->> impls
                       (filter (fn [[_ methods]] (get methods method)))
                       (map first)
                       (filter #(inheritance/inherits? % type))
                       seq))))))
link
(implements? state/IStateGet clojure.lang.Atom) => true (implements? state/IStateGet clojure.lang.Atom "-get-state") => true

protocol-impls ^

returns types that implement the protocol

v 3.0
(defn protocol-impls
  [protocol]
  (-> protocol :impls keys set))
link
(protocol-impls state/IStateSet) => (contains [clojure.lang.Agent clojure.lang.Ref clojure.lang.IAtom clojure.lang.Volatile clojure.lang.IPending clojure.lang.Var] :in-any-order :gaps-ok) (protocol-impls state/IStateGet) => (contains [clojure.lang.IDeref clojure.lang.IPending] :in-any-order :gaps-ok)

protocol-interface ^

returns the java interface for a given protocol

v 3.0
(defn protocol-interface
  [protocol]
  (-> protocol :on-interface))
link
(protocol-interface state/IStateGet) => hara.protocol.state.IStateGet

protocol-methods ^

returns the methods provided by the protocol

v 3.0
(defn protocol-methods
  [protocol]
  (->> protocol :sigs vals (map :name) sort vec))
link
(protocol-methods state/IStateSet) => '[-clone-state -empty-state -set-state -update-state]

protocol-remove ^

removes a protocol

v 3.0
(defn protocol-remove
  [protocol atype]
  (-reset-methods (alter-var-root (:var protocol) update-in [:impls] dissoc atype)))
link
(defprotocol -A- (-dostuff [_])) (do (extend-protocol -A- String (-dostuff [_])) (implements? -A- String "-dostuff")) => true (do (protocol-remove -A- String) (implements? -A- String "-dostuff")) => false

protocol-signatures ^

returns the method signatures provided by the protocol

v 3.0
(defn protocol-signatures
  [protocol]
  (->> (:sigs protocol) 
       (reduce (fn [out [_ m]]
                 (assoc out (:name m) (dissoc m :name)))
               {})))
link
(protocol-signatures state/IStateSet) => '{-update-state {:arglists ([obj f args opts]) :doc nil} -set-state {:arglists ([obj v opts]) :doc nil} -empty-state {:arglists ([obj opts]) :doc nil} -clone-state {:arglists ([obj opts]) :doc nil}}

protocol? ^

checks whether an object is a protocol

v 3.0
(defn protocol?
  [obj]
  (boolean (and (instance? clojure.lang.PersistentArrayMap obj)
                (every? #(contains? obj %) [:on :on-interface :var])
                (-> obj :on str Class/forName error/suppress)
                (protocol-interface obj))))
link
(protocol? state/IStateGet) => true

11    Result



->data ^

NONE
(defn ->data
  [res]
  (if (result? res) (:data res) res))
example not found

->result ^

converts data into a result

v 3.0
(defn ->result
  [key data]
  (cond (result? data)
        (assoc data :key key)

        :else
        (result {:key key :status :return :data data})))
link
(->result :hello [1 2 3]) ;;#result.return{:data [1 2 3], :key :hello} => hara.core.base.result.Result

result ^

creates a result used for printing

v 3.0
(defn result
  [m]
  (map->Result m))
link
(result {:status :warn :data [1 2 3 4]}) ;; #result{:status :warn, :data [1 2 3 4]} => hara.core.base.result.Result

result? ^

checks if an object is a result

v 3.0
(defn result?
  [obj]
  (instance? Result obj))
link
(-> (result {:status :warn :data [1 2 3 4]}) result?) => true

12    Shorthand



call-> ^

indirect call, takes `obj` and a list containing either a function, a symbol representing the function or the symbol `?` and any additional arguments. Used for calling functions that have been stored as symbols.

v 3.0
(defn call->
  [obj [ff & args]]
  (cond (nil? ff)     obj
        (list? ff)    (recur (call-> obj ff) args)
        (vector? ff)  (recur (get-in obj ff) args)
        (keyword? ff) (recur (get obj ff) args)
        (fn? ff)      (apply ff obj args)
        (symbol? ff)  (if-let [f (do
                                   (error/suppress (require (symbol (namespace ff))))
                                   (error/suppress (resolve ff)))]
                        (apply fn/invoke f obj args)
                        (recur (get obj ff) args))
        :else         (recur (get obj ff) args)))
link
(call-> 1 '(+ 2 3 4)) => 10 (call-> 1 '(< 2)) => true (call-> {:a {:b 1}} '((get-in [:a :b]) = 1)) => true

check ^

checks

v 3.0
(defn check
  ([obj chk]
   (or (= obj chk)
       (-> (get-> obj chk) not not)))
  ([obj sel chk]
   (check (get-> obj sel) chk)))
link
(check 2 2) => true (check 2 even?) => true (check 2 '(> 1)) => true (check {:a {:b 1}} '([:a :b] (= 1))) => true (check {:a {:b 1}} :a vector?) => false (check {:a {:b 1}} [:a :b] 1) => true

check-> ^

shorthand ways of checking where `m` fits `prchk`

v 3.0
(defn check->
  [obj pchk]
  (cond (vector? pchk)
        (apply check-all obj pchk)

        (set? pchk)
        (or (some true? (map #(check-> obj %) pchk))
            false)

        :else
        (check obj pchk)))
link
(check-> {:a 1} :a) => true (check-> {:a 1 :val 1} [:val 1]) => true (check-> {:a {:b 1}} [[:a :b] odd?]) => true

check-all ^

returns `true` if `obj` satisfies all pairs of sel and chk

v 3.0
(defn check-all
  [obj & pairs]
  (every? (fn [[sel chk]]
            (check obj sel chk))
          (partition 2 pairs)))
link
(check-all {:a {:b 1}} :a #(instance? clojure.lang.IPersistentMap %) [:a :b] 1) => true

check?-> ^

tests obj using prchk and returns `obj` or `res` if true

v 3.0
(defn check?->
  ([obj prchk] (check?-> obj prchk true))
  ([obj prchk res]
   (error/suppress (if (check-> obj prchk) res))))
link
(check?-> :3 even?) => nil (check?-> 3 even?) => nil (check?-> 2 even?) => true (check?-> {:id :1} '[:id (= :1)]) => true

eq-> ^

compare if two vals are equal.

v 3.0
(defn eq->
  [obj1 obj2 sel]
  (= (get-> obj1 sel) (get-> obj2 sel)))
link
(eq-> {:id 1 :a 1} {:id 1 :a 2} :id) => true (eq-> {:db {:id 1} :a 1} {:db {:id 1} :a 2} [:db :id]) => true

fn-> ^

constructs a function from a form representation.

v 3.0
(defn fn->
  [form]
  (eval (shorthand-fn-expr form)))
link
((fn-> '(+ 10)) 10) => 20

get-> ^

provides a shorthand way of getting a return value. `sel` can be a function, a vector, or a value.

v 3.0
(defn get->
  [obj sel]
  (cond (nil? sel)    obj
        (list? sel)   (call-> obj sel)
        (vector? sel) (get-in obj sel)
        (symbol? sel) (if-let [f (do (if-let [nsp (.getNamespace ^clojure.lang.Symbol sel)]
                                       (require (symbol nsp)))
                                     (error/suppress (resolve sel)))]
                        (fn/invoke f obj)
                        (get obj sel))
        (ifn? sel)    (sel obj)
        :else         (get obj sel)))
link
(get-> {:a {:b {:c 1}}} :a) => {:b {:c 1}} (get-> {:a {:b {:c 1}}} [:a :b]) => {:c 1}

shorthand-fn-expr ^

makes a function expression out of the form

v 3.0
(defn shorthand-fn-expr
  [form]
  (apply list 'fn ['?]
         (list (shorthand-form '? form))))
link
(shorthand-fn-expr '(+ 2)) => '(fn [?] (+ ? 2))

shorthand-form ^

makes an expression using `sym`

v 3.0
(defn shorthand-form
  [sym [ff & more]]
  (cond (nil? ff)     sym
        (list? ff)    (recur (shorthand-form sym ff) more)
        (vector? ff)  (recur (list 'get-in sym ff) more)
        (keyword? ff) (recur (list 'get sym ff) more)
        (symbol? ff)  (apply list ff sym more)
        :else         (recur (list 'get sym ff) more)))
link
(shorthand-form 'y '(str)) => '(str y) (shorthand-form 'x '((inc) (- 2) (+ 2))) => '(+ (- (inc x) 2) 2)

13    Sort



hierarchical-sort ^

prunes a hierarchy of descendants into a directed graph

v 3.0
(defn hierarchical-sort
  [idx]
  (let [top (hierarchical-top idx)]
    (loop [out {}
           candidates (dissoc idx top)
           level #{top}]
      (if (empty? level)
        out
        (let [base  (apply set/union (vals candidates))
              out   (reduce (fn [out i]
                              (assoc out i (set/difference (get idx i) base)))
                            out
                            level)
              nlevel (mapcat #(get out %) level)
              ncandidates (apply dissoc idx (concat (keys out) nlevel))]
          (recur out
                 ncandidates
                 nlevel))))))
link
(hierarchical-sort {1 #{2 3 4 5 6} 2 #{3 5 6} 3 #{5 6} 4 #{} 5 #{6} 6 #{}}) => {1 #{4 2} 2 #{3} 3 #{5} 4 #{} 5 #{6} 6 #{}}

hierarchical-top ^

find the top node for the hierarchy of descendants

v 3.0
(defn hierarchical-top
  [idx]
  (let [rest (apply set/union (vals idx))]
    (ffirst (filter (fn [[k v]]
                      (not-empty (set/difference (conj v k) rest)))
                    idx))))
link
(hierarchical-top {1 #{2 3 4 5 6} 2 #{3 5 6} 3 #{5 6} 4 #{} 5 #{6} 6 #{}}) => 1

topological-sort ^

sorts a directed graph into its dependency order

v 3.0
(defn topological-sort
  ([g]
   (let [g (let [dependent-nodes (apply set/union (vals g))]
             (reduce #(if (get % %2) % (assoc % %2 #{})) g dependent-nodes))]
     (topological-sort g () (topological-top g))))
  ([g l s]
   (cond (empty? s)
         (if (every? empty? (vals g))
           l
           (throw (ex-info "Graph Contains Circular Dependency."
                           {:data (->> g
                                       (filter (fn [[k v]] (-> v empty? not)))
                                       (into {}))
                            :list l})))

         :else
         (let [[n s*] (if-let [item (first s)]
                        [item (set/difference s #{item})])
               m (g n)
               g* (reduce #(update-in % [n] set/difference #{%2}) g m)]
           (recur g* (cons n l) (set/union s* (set/intersection (topological-top g*) m)))))))
link
(topological-sort {:a #{:b :c}, :b #{:d :e}, :c #{:e :f}, :d #{}, :e #{:f}, :f nil}) => [:f :d :e :b :c :a] (topological-sort {:a #{:b}, :b #{:a}}) => (throws)

topological-top ^

nodes that have no other nodes that are dependent on them

v 3.0
(defn topological-top
  [g]
  (let [nodes (set (keys g))
        dependent-nodes (apply set/union (vals g))]
    (set/difference nodes dependent-nodes)))
link
(topological-top {:a #{} :b #{:a}}) => #{:b}

14    Util



^

returns `false` for any combination of input `args`

v 3.0
(defn F
  [& args] false)
link
(F) => false (F :hello) => false (F 1 2 3) => false

NIL ^

returns `nil` for any combination of input `args`

v 3.0
(defn NIL
  [& args] nil)
link
(NIL) => nil (NIL :hello) => nil (NIL 1 2 3) => nil

^

returns `true` for any combination of input `args`

v 3.0
(defn T
  [& args] true)
link
(T) => true (T :hello) => true (T 1 2 3) => true

hash-label ^

returns a keyword repesentation of the hash-code. For use in generating internally unique keys

v 3.0
(defn hash-label
  ([^Object obj] (str "__" (.hashCode obj) "__"))
  ([^Object obj & more]
   (let [result (->> (cons obj more)
                     (map (fn [^Object x] (.hashCode x)))
                     (clojure.string/join "_"))]
     (str "__" result "__"))))
link
(hash-label 1) => "__1__" (hash-label "a" "b" "c") => "__97_98_99__" (hash-label "abc") => "__96354__"

instant ^

returns a `java.util.Date` object

v 3.0
(defn instant
  ([] (java.util.Date.))
  ([^Long val] (java.util.Date. val)))
link
(instant) => #(instance? java.util.Date %) (instant 0) => #inst "1970-01-01T00:00:00.000-00:00"

queue ^

returns a `clojure.lang.PersistentQueue` object.

v 3.0
(defn queue
  ([] (clojure.lang.PersistentQueue/EMPTY))
  ([x] (conj (queue) x))
  ([x & xs] (apply conj (queue) x xs)))
link
(def a (queue 1 2 3 4)) (pop a) => [2 3 4]

uri ^

returns a `java.net.URI` object

v 3.0
(defn uri
  [path] (java.net.URI/create path))
link
(uri "http://www.google.com") => #(instance? java.net.URI %)

uuid ^

returns a `java.util.UUID` object

v 3.0
(defn uuid
  ([] (java.util.UUID/randomUUID))
  ([id]
   (cond (string? id)
         (java.util.UUID/fromString id)

         (instance? (Class/forName "[B") id)
         (java.util.UUID/nameUUIDFromBytes id)

         :else
         (throw (ex-info (str id " can only be a string or byte array")))))
  ([^Long msb ^Long lsb]
   (java.util.UUID. msb lsb)))
link
(uuid) => #(instance? java.util.UUID %) (uuid "00000000-0000-0000-0000-000000000000") => #uuid "00000000-0000-0000-0000-000000000000"