Snitch is inline-defs on steroids
Snitch is how I debug and understand data flowing through my system. It's not a replacement for a full-fledged debugger, but it's pretty close and will be useful in 90% of the cases. I use it as my sole debugger (in rare cases I reach for print statements).
There are four macros defn*, defmethod* *fn, *let.
They are drop-in replacements for defn, defmethod, fn, and let.
These macros creates inline defs of the parameters passed to the functions, and also inside the let bindings of the functions. This makes it very "ergonomic" for repl-driven development.
(require '[snitch.core :refer [defn*]])
(defn* foo [a b]
(+ a b)
nil)
;; calling foo with random integers
(foo (rand-int 100) (rand-int 100)) ; nil
;; we can evaluate the value of a and b
a ; 15
b ; 85
;; we can get the return value of foo by appending a < to foo
foo<
=> nil
;; it roughly expands to a form that looks like this.
;; the actual macro expansion is more complex.
(clojure.core/defn
foo
[a b]
(def a a)
(def b b)
(clojure.core/let
[result__12589__auto__ (do (+ a b) nil)]
(def foo< result__12589__auto__)
result__12589__auto__))
A more complex example
(require '[snitch.core :refer [defn*]])
(defn* foo1 [{:keys [a/b1 c2]
dee3 :d3
:as m4}
[x5 [y6 [z7]]]]
[b1 c2 dee3 m4 x5 y6 z7])
;; there is some crazy destructuring going on in the function parameters.
;; snitch handles this with ease
(foo1 {:a/b1 1 :c2 2 :d3 3 :e 100 :f 200}
[5 [6 [7]]])
;=> [1 2 3 {:a/b1 1, :c2 2, :d3 3} 5 6 7]
;; we can evaluate each var.
b1 ; 1
dee3 ; 3
m4 ; {:a/b1 1, :c2 2, :d3 3}
z7 ; 7
foo1< ; [1 2 3 {:a/b1 1, :c2 2, :d3 3} 5 6 7]
;; now for the coolest feature (IMO).
;; imagine a case where foo1 was called in some namespace ( you don't really know what was passed to it)
;; but there is a bug in foo1 that you want to fix
;; how do you reconstruct the function call?
;; we have the parameters defined, but you can't do this
(foo1 b1 dee3....)
;; because it needs to be passed a map and a vector.
;; constructing the map is very painful and time consuming.
;; snitch provides functionality for that too.
;; just evaluate foo1>
foo1> ; (foo1 {:a/b1 1, :c2 2, :d3 3} [5 [6 [7]]])
;; foo1> returns a list that can be evaluated
;; notice that when snitch reconstructed the function call,
;; it left out the keys :e and :f?
;; the original map passed was {:a/b1 1 :c2 2 :d3 3 :e 100 :f 200}
;; snitch is smart that way and only constructs the arguments absolutely necessary
;; for the function call.
I'd recommend adding snitch to your ~/.lein/profiles.clj.
An example file would be
; profiles.clj
{:user {:dependencies [[org.clojars.abhinav/snitch "0.0.11"]]}}
{:dev {:dependencies [[org.clojars.abhinav/snitch "0.0.11"]]}}
Snitch works with clojurescript as well.
you can add the dependency to ~/.shadow-cljs/config.edn
{:dependencies
[[org.clojars.abhinav/snitch "0.0.11"]]}
The import for clojurescript looks different.
(:require [snitch.core :refer-macros [defn*]])
Writing the (require '[snitch.core :refer [defn*]]) in every namespace is cumbersome (if you know a way to globally define defn* for all namespaces let me know yesterday!).
I have two vim macros that inject require at the top of my ns, and evaluate it.
"for clj
let @s = "m8gg0)o(require 'jkf'xi[snitch.core :refer [defn* defmethod* *fn *let]])jk;ee`8"
"for cljs
let @n = "m8gg0>I(:require [snitch.core :refer-macros [defn* defmethod* *fn *let]])jk;er`8"
the macro does the following things.
;ee (conjure's evaluation command)the macro is specific to my config, but the steps will give you an idea to create your own macros.
if you have created any specific macros/workflows for your editor of choice, you can open a PR and add it to the readme :)
Can you improve this documentation? These fine people already did:
AbhinavOmprakash & Abhinav OmprakashEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |