diff options
Diffstat (limited to 'users/aspen/bbbg/src/bbbg/util/core.clj')
-rw-r--r-- | users/aspen/bbbg/src/bbbg/util/core.clj | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/users/aspen/bbbg/src/bbbg/util/core.clj b/users/aspen/bbbg/src/bbbg/util/core.clj new file mode 100644 index 000000000000..d458aa5592d2 --- /dev/null +++ b/users/aspen/bbbg/src/bbbg/util/core.clj @@ -0,0 +1,138 @@ +(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)))))) |