blob: d458aa5592d286445a26d195581eb7a2c4e4924b (
plain) (
tree)
|
|
(ns bbbg.util.core
(:require
[clojure.java.shell :refer [sh]]
[clojure.string :as str])
(:import
java.util.UUID))
(defn remove-nils
"Remove all keys with nil values from m"
[m]
(let [!m (transient m)]
(doseq [[k v] m]
(when (nil? v)
(dissoc! !m k)))
(persistent! !m)))
(defn alongside
"Apply a pair of functions to the first and second element of a two element
vector, respectively. The two argument form partially applies, such that:
((alongside f g) xy) ≡ (alongside f g xy)
This is equivalent to (***) in haskell's Control.Arrow"
([f g] (partial alongside f g))
([f g [x y]] [(f x) (g y)]))
(defn map-kv
"Map a pair of functions over the keys and values of a map, respectively.
Preserves metadata on the incoming map.
The two argument form returns a transducer that yields map-entries.
(partial map-kv identity identity) ≡ identity"
([kf vf]
(map (fn [[k v]]
;; important to return a map-entry here so that callers down the road
;; can use `key` or `val`
(first {(kf k) (vf v)}))))
([kf vf m]
(into (empty m) (map-kv kf vf) m)))
(defn filter-kv
"Returns a map containing the elements of m for which (f k v) returns logical
true. The one-argument form returns a transducer that yields map entries"
([f] (filter (partial apply f)))
([f m]
(into (empty m) (filter-kv f) m)))
(defn map-keys
"Map f over the keys of m. Preserves metadata on the incoming map. The
one-argument form returns a transducer that yields map-entries."
([f] (map-kv f identity))
([f m] (map-kv f identity m)))
(defn keep-keys
"Map f over the keys of m, keeping only those entries for which f does not
return nil. Preserves metadata on the incoming map. The one-argument form
returns a transducer that yields map-entries."
([f] (keep (fn [[k v]] (when-let [k' (f k)]
(first {k' v})))))
([f m] (into (empty m) (keep-keys f) m)))
(defn map-vals
"Map f over the values of m. Preserves metadata on the incoming map. The
one-argument form returns a transducer that yields map-entries."
([f] (map-kv identity f))
([f m] (map-kv identity f m)))
(defn map-keys-recursive [f x]
(cond
(map? x) (map-kv f (partial map-keys-recursive f) x)
(sequential? x) (map (partial map-keys-recursive f) x)
:else x))
(defn denamespace [x]
(if (keyword? x)
(keyword (name x))
(map-keys-recursive denamespace x)))
(defn reverse-merge
"Like `clojure.core/merge`, except duplicate keys from maps earlier in the
argument list take precedence
=> (merge {:x 1} {:x 2})
{:x 2}
=> (sut/reverse-merge {:x 1} {:x 2})
{:x 1}"
[& ms]
(apply merge (reverse ms)))
(defn invert-map
"Invert the keys and vals of m. Behavior with duplicate vals is undefined.
=> (sut/invert-map {:x 1 :y 2})
{1 :x 2 :y}"
[m]
(into {} (map (comp vec reverse)) m))
(defn ->uuid
"Converts x to uuid, returning nil if x is nil or empty"
[x]
(cond
(not x) nil
(uuid? x) x
(and (string? x) (seq x))
(UUID/fromString x)))
(defn key-by
"Create a map from a seq obtaining keys via f
=> (sut/key-by :x [{:x 1} {:x 2 :y 3}])
{1 {:x 1}, 2 {:x 2 :y 3}}"
[f l]
(into {} (map (juxt f identity)) l))
(defn distinct-by
"Like clojure.core/distinct, but can take a function f by which
distinctiveness is calculated"
[distinction-fn coll]
(let [step (fn step [xs seen]
(lazy-seq
((fn [[f :as xs] seen]
(when-let [s (seq xs)]
(if (contains? seen (distinction-fn f))
(recur (rest s) seen)
(cons f (step (rest s) (conj seen (distinction-fn f)))))))
xs seen)))]
(step coll #{})))
(defn pass [n]
(let [{:keys [exit out err]} (sh "pass" n)]
(if (= 0 exit)
(str/trim out)
(throw (Exception.
(format "`pass` command failed\nStandard output:%s\nStandard Error:%s"
out
err))))))
|