Skip to content

Instantly share code, notes, and snippets.

@danieroux
Created February 24, 2024 11:29
Show Gist options
  • Save danieroux/dfb277f47b74fc61c87a92d47edd8c5a to your computer and use it in GitHub Desktop.
Save danieroux/dfb277f47b74fc61c87a92d47edd8c5a to your computer and use it in GitHub Desktop.
Monkey patching clojure.core for dev convenience
;; Load this in user.clj with:
; (load "monkey_patch_clojure_core")
(ns monkey-patch-clojure-core
(:require
[taoensso.timbre :as log]))
(log/info "Monkey patching clojure.core, adding:")
(log/info (str " " 'ddef))
(log/info (str " " 'unddef))
(log/info (str " " 'profile))
(log/info (str " " 'gen-one))
(log/info (str " " 'gen-sample))
(log/info (str " " 'pbcopy))
(log/info (str " " 'pbcopy-pr))
(ns clojure.core)
(defmacro ddef
"Sugar:
(ddef x y z) -> (def x x) (def y y) (def x x)"
[& names]
(cons
'do
(map
(fn [n]
`(def ~n ~n))
names)))
(defmacro unddef
[& names]
(cons
'do
(map
(fn [n]
`(ns-unmap *ns* (quote ~n)))
names)))
(require '[clj-async-profiler.core])
(defmacro profile
"Profile the execution of `body`. If the first argument is a map, treat it as
options. For available options, see `start` and `stop`. `:pid` option is
ignored, current process is always profiled. Additional options:
:return-file - if true, return the generated flamegraph file, otherwise return
the value returned by `body` (default: false - return value)"
{:matter.dev/copied-from "https://github.com/clojure-goes-fast/clj-async-profiler/blob/master/src/clj_async_profiler/core.clj#L349"
:matter.dev/why "Easy profiling. Open the file profile.clj and load it, after you profiled"}
[options? & body]
(let [[options body] (if (map? options?)
[(dissoc options? :pid) body]
[{} (cons options? body)])]
`(let [options# ~options
_# (println (clj-async-profiler.core/start options#))
f# (atom nil)
ret# (try ~@body
(finally (reset! f# (clj-async-profiler.core/stop options#))))]
(if (:return-file options#)
@f# ret#))))
(defn gen-one
"Gen one of the given spec, setting recursion limit.
Override recursion limit with :recursion-limit"
[spec & {:keys [recursion-limit]
:or {recursion-limit 1}}]
(require 'clojure.spec.alpha)
(require 'clojure.spec.gen.alpha)
(binding [clojure.spec.alpha/*recursion-limit* recursion-limit]
(clojure.spec.gen.alpha/generate (clojure.spec.alpha/gen spec))))
(defn gen-sample
"Gen a sample of the given spec, setting recursion limit.
Override size with :sample-size.
Override recursion limit with :recursion-limit"
[spec & {:keys [sample-size recursion-limit]
:or {sample-size 10
recursion-limit 1}}]
(require 'clojure.spec.alpha)
(require 'clojure.spec.gen.alpha)
(binding [clojure.spec.alpha/*recursion-limit* recursion-limit]
(clojure.spec.gen.alpha/sample
(clojure.spec.alpha/gen spec)
sample-size)))
(defmacro pbcopy
"OSX Super convenience: The result of form will be in the OSX paste buffer.
Assumes string."
[& body]
`(clojure.java.shell/sh "pbcopy" :in ~@body))
(defmacro pbcopy-pr
"OSX Super convenience: The result of form will be in the OSX paste buffer, after pr-str
A cleverer thing can happen here: `:in` could be `*out*`. Later."
[& body]
`(clojure.java.shell/sh "pbcopy" :in (pr-str ~@body)))
(comment
(pbcopy "Hello pbcopy")
(macroexpand-1 `(pbcopy-pr (hash-map :a 5)))
(pbcopy-pr (hash-map :a 5))
(pbcopy-pr {:a 5})
())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment