Instantly share code, notes, and snippets.

🌚
┬━┬ノ(▀̿̿Ĺ̯̿̿▀̿ ̿ノ)

Paul Rutledge RutledgePaulV

View GitHub Profile
View let-from-map.clj
(defmacro evaluate* [bindings & code]
(letfn [(eval-with-bindings [bindings code]
(let [ks (keys bindings)]
((eval `(fn [{:syms [~@ks]}] ~code)) bindings)))]
`(~eval-with-bindings ~bindings '(do ~@code))))
@RutledgePaulV
RutledgePaulV / with-redefs.clj
Created Oct 31, 2018
Like with-redefs but local to the thread. Doesn't require dynamic function vars.
View with-redefs.clj
(def ^:dynamic *hook* false)
(defn hook [var f]
(alter-var-root var
(fn [original]
(fn [& args]
(if *hook*
(apply f args)
(apply original args))))))
@RutledgePaulV
RutledgePaulV / hooks.clj
Created Oct 29, 2018
Few functions are dynamic vars. Make them dynamic after the fact by adding a second implementation that only runs for specific threads.
View hooks.clj
(defonce ^:dynamic *hooked* false)
(defn hook [var f]
(alter-var-root var
(fn [original]
(fn [& args]
(if *hooked*
(apply f args)
(apply original args))))))
@RutledgePaulV
RutledgePaulV / cached.clj
Last active Nov 27, 2018
A macro for memoization of a body of code based on the values of all referenced vars (implicit memoization key instead of explicit arguments). Probably a terrible idea.
View cached.clj
(defmacro cached [& body]
(let [dependencies (transient #{})
resolved (walk/postwalk
(fn [form]
(if (symbol? form)
(if-some [resolved (resolve &env form)]
(when (var? resolved)
(conj! dependencies resolved)
(.toSymbol ^Var resolved))
form)
View defqueue.clj
(require '[clojure.core.async :as async])
(require '[mount.core :as mount])
(defn work-queue [buffer max-retries parallelism]
(let [chan (async/chan buffer)]
(dotimes [_ parallelism]
(async/go-loop []
(when-some [i (async/<! chan)]
(let [{:keys [f retries]} (if (map? i) i {:retries 0 :f i})]
(try (f)
@RutledgePaulV
RutledgePaulV / core-async-pipeline-bug.clj
Last active Sep 4, 2018
core-async-pipeline-bug.clj
View core-async-pipeline-bug.clj
(require '[clojure.test :refer :all])
(require '[clojure.core.async :as async])
(deftest from-channel-still-consumed-after-to-channel-is-closed
(let [from-counter (atom 0)
xf-counter (atom 0)
from (async/chan)
to (async/chan 1000)
xf (map #(do (Thread/sleep 100)
(swap! xf-counter inc)
@RutledgePaulV
RutledgePaulV / locking.clj
Created Nov 6, 2017
Some macros for locking by value.
View locking.clj
(def ^:dynamic *locks* (atom {}))
(defn new-lock []
{:count 1 :ref (Object.)})
(defn inc-lock [lock]
(when lock (update lock :count inc)))
(defn dec-lock [lock]
View nor.clj
(defmacro nor [& more]
(conj `~(partition 2 (interleave (repeat 'not) more)) 'and))
View chan-cleanup.clj
(defn attach-channel-cleanup [chan f]
(add-watch (.closed chan)
"channel-resource-cleanup"
(fn [_ _ old-state new-state]
(when (and (not old-state) new-state)
(f))))
chan)
View remove-replace-warnings.clj
; add this to your project.clj file to suppress compilation warnings
:injections
[(alter-var-root clojure.lang.RT/ERR
(constantly
(java.io.PrintWriter.
(org.apache.commons.io.output.NullWriter.))))]