Skip to content

Instantly share code, notes, and snippets.

View RutledgePaulV's full-sized avatar

Paul Rutledge RutledgePaulV

View GitHub Profile
@RutledgePaulV
RutledgePaulV / self-cleaning-pool.clj
Last active July 7, 2022 19:57
self-cleaning-pool.clj
(defn gc-managed-pool
"Wraps a manually managed pool to create an automatically managed pool
that returns resources to the pool as the doled out references are
garbage collected by the jvm."
[pool borrow return]
(letfn [(interfaces [x]
(->> (ancestors (class x))
(filter class?)
(filter #(.isInterface %))))
(create-facade [x]
@RutledgePaulV
RutledgePaulV / let-from-map.clj
Created January 2, 2019 02:27
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 October 31, 2018 19:41
Like with-redefs but local to the thread. Doesn't require dynamic function vars.
(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 October 29, 2018 13:13
Few functions are dynamic vars. Make them dynamic after the fact by adding a second implementation that only runs for specific threads.
(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 November 27, 2018 06:17
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.
(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)
@RutledgePaulV
RutledgePaulV / defqueue.clj
Last active October 11, 2018 03:15
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 September 4, 2018 06:48
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 November 6, 2017 13:42
Some macros for locking by value.
(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]
(defmacro nor [& more]
(conj `~(partition 2 (interleave (repeat 'not) more)) 'and))
(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)