Small yet effective Clojure weapons.
Yamato Takeru dressed as a maidservant, preparing to kill the Kumaso leaders.
[net.clojars.unexpectedness/shuriken "0.14.53"]
(ns my-ns
(:require [shuriken.core :refer :all]))
Libraries that were originally part of shuriken.
map-keys & map-vals.filter-keys & filter-vals.remove-keys & remove-vals.submap?.flatten-keys(flatten-keys {:a {:b {:c :x
:d :y}}})
;; {[:a :b :c] :x
;; [:a :b :d] :y}
deflatten-keys(deflatten-keys {[:a :b :c] :x
[:a :b :d] :y})
;; {:a {:b {:c :x
;; :d :y}}}
deep-merge(deep-merge {:x {:a :a :b :b :c :c}}
{:x {:a :aa :b :bb}}
{:x {:a :aaa}})
;; {:x {:a :aaa :b :bb :c :c}}
index-by(def ms [{:a 1 :b 2} {:a 3 :b 4} {:a 5 :b 4}])
(index-by :a ms)
;; {1 {:a 1 :b 2}
;; 3 {:a 3 :b 4}
;; 5 {:a 5 :b 4}}
(index-by :b ms)
;; clojure.lang.ExceptionInfo (Duplicate entries for key 4)
(index-by :b (fn [key entries]
(last entries))
ms)
;; {2 {:a 1 :b 2}
;; 4 {:a 5 :b 4}}
split-map(let [m {:a 1 :b 2 :c 3 :d 4}]
(split-map m [:a :b]) ;; [{:a 1 :b 2} {:c 3 :d 4}]
(split-map m [:a :b] [:c])) ;; [{:a 1 :b 2} {:c 3} {:d 4}]
map-difference(let [m {:a 1 :b 2 :c 3}]
(map-difference m {:a :x}) ;; {:b 2 :c 3}
(map-difference m {:a :x} {:b :x})) ;; {:c 3}
map-intersection(let [m {:a 1 :b 2 :c 3}]
(map-intersection m {:a :x}) ;; {:a 1}
(map-intersection m {:a :x :b :x}) ;; {:a 1 :b 2}
(map-intersection m {:a :x} {:b :x}) ;; {}
(map-intersection m {}) ;; {}
(map-intersection m nil)) ;; {}
getsocWorks like get if the key is present in the hash, else works like assoc.
Returns a vector of the form [get-or-stored-value new-coll].
(getsoc {:a 1} :a (constantly 2)) ;; => [1 {:a 1}]
(getsoc {} :a (constantly 2))) ;; => [2 {:a 2}]
silence(silence ArithmeticException (/ 1 0))
;; => nil
(silence [ArithmeticException]
(do (println "watch out !")
(/ 1 0)))
;; watch out !
;; => nil
(silence "Divide by zero" (/ 1 0))
;; => nil
(silence #"zero" (/ 1 0))
;; => nil
(silence :substitute
(fn [x]
(isa? (class x) ArithmeticException))
(/ 1 0))
;; => :substitute
thrown?(thrown? ArithmeticException (/ 1 0))
;; => true
(thrown? "Divide by zero" (/ 1 0))
;; => true
(thrown? #"zero" (/ 1 0))
;; => true
(thrown? #{ArithmeticException} (/ 1 1))
;; => false
(thrown? (fn [x]
(isa? (class x) ArithmeticException))
(throw (IllegalArgumentException. "my-error")))
;; raises:
;; IllegalArgumentException my-error
(thrown? {:type :oops}
(throw (ex-info "Oops" {:type :oops :value :abc})))
;; => true
get-nth, get-nth-in, assoc-nth, assoc-nth-in, update-nth & update-nth-inRespectively like get, get-in, assoc etc... but also work on lists.
insert-atInsert an item into a list or a vector.
(insert-at [1 2 3] 0 :x) ;; => [:x 1 2 3]
(insert-at '(1 2 3) 1 :x) ;; => '(1 :x 2 3)
(insert-at '(1 2 3) 3 :x) ;; => '(1 2 3 :x)
(insert-at [1 2 3] 4 :x) ;; => java.lang.IndexOutOfBoundsException
(insert-at [1 2 3] -1 :x) ;; => java.lang.IndexOutOfBoundsException
slice(let [coll [1 1 0 1 0 0 1 1]]
;; the default
(slice zero? coll) ;; by default, :include-delimiter false, include-empty true
;; ((1 1) (1) (1 1))
(slice zero? coll :include-empty true)
;; ((1 1) (1) () (1 1))
(slice zero? coll :include-delimiter :left)
;; ((1 1) (0 1) (0 1 1))
(slice zero? coll :include-delimiter :right)
;; ((1 1 0) (1 0) (1 1))
(slice zero? coll :include-delimiter :right :include-empty true)
;; ((1 1 0) (1 0) (0) (1 1))
)
separateReturns a vector of [(filter pred coll) (remove pred coll)].
(let [coll [1 1 0 1 0 0 1 1 0]]
(separate zero? coll)
;; [(1 1 1 1 1) (0 0 0 0)]
)
orderOrder a sequence with constraints.
(order [1 2 3] {2 1 3 :all})
(order [1 2 3] [[2 1] [3 :all]])
(order [1 2 3] [[2 :before 1] [:all :after 3]])
(order [1 2 3] [[2 :> 1] [:all :< 3]])
;; (3 2 1)
takesSplit a sequence in subsequence of predetermined length.
(takes [1 2 3] [:a :b]) ;; => ((:a) (:b))
(takes [1 2 3] [:a :b :c]) ;; => ((:a) (:b :c))
(takes [1 2 3] [:a :b :c :d :e :f]) ;; => ((:a) (:b :c) (:d :e :f))
(takes [1 2 3] [:a :b :c :d :e :f :g]) ;; => ((:a) (:b :c) (:d :e :f) (:g))
(takes [0 0 1 0 2] [:a :b :c :d :e]) ;; => (() () (:a) () (:b :c) (:d :e))
(is-form? 'a 1) ; false
(is-form? 'a '[a :z]) ; false
(is-form? 'a '(a :z)) ; true
(wrap-form 'a :z) ; (a :z)
(->> :z (wrap-form 'a) (wrap-form 'a)) ; (a :z)
(unwrap-form 'a '(a :z)) ; a
(->> '(a :z) (unwrap-form 'a) (unwrap-form 'a)) ; a
clean-codeRecursively unqualifies qualified code in the provided form.
(clean-code `(a (b c)))
;; (a (b c))
file-evalEvaluate code in a temporary file via load-file in the local lexical context. Keep the temporary file aside if an error is raised, deleting it on the next run.
(let [a 1]
(file-eval '(+ 1 a)))
Code evaluated this way will be source-mapped in stacktraces.
macroexpand-nIteratively call macroexpand-1 on form n times.
(defmacro d [x] x)
(defmacro c [x] `(d ~x))
(defmacro b [x] `(c ~x))
(defmacro a [x] `(b ~x))
(macroexpand-n 2 '(a 1))
; (my-ns/c 1)
macroexpand-someRecursively macroexpand forms whose first element match a filter. Symbols are passed to filter unqualified.
(defmacro by [code]
`(inc ~code))
(defmacro az [code]
`(by ~code))
(macroexpand-some '#{az} '(az (+ 1 2)))
; => (user/by (+ 1 2))
macroexpand-do(defmacro abc []
`(println "xyz"))
(macroexpand-do (abc))
; -- Macro expansion --
; (clojure.core/println "xyz")
; -- Running macro --
; xyz
or alternatively:
(macroexpand-do MODE
form)
Where MODE has the following meaning:
MODE | expansion |
|---|---|
nil (the default) | macroexpand |
:all | clojure.walk/macroexpand-all |
| a number n | iterate macroexpand-1 n times |
| anything else | a predicate to macroexpand-some |
To allow for better tracking of exceptions in code generated by macros,
macroexpand-do evaluates the expansion of the macro expression in a temporary
file that is kept aside for inspection and appears in the stacktrace of raised
exceptions. If no exception is raised, the file is deleted.
without-meta(meta (without-meta (with-meta [1 2 3] {:metadata :abc}))) ;; nil
monkey-patch(monkey-patch :perfid-incer clojure.core/+ [original & args]
(inc (apply original args)))
Supports reload. Name and target can be vars or quoted symbols.
onceEnsures the code is executed only once with respect to the associated name. name must be a symbol, quoted or not.
(once 'only-once (println "printed once"))
(once 'only-once (println "printed once"))
;; printed once
refresh-once(once 'a (println "a"))
;; a
(once 'a (println "a"))
;; prints nothings
(refresh-once 'a)
(once 'a (println "a"))
;; a
fully-qualifyReturns the fully-qualified form of the symbol as if resolved from within a namespace.
(fully-qualified? 'IRecord) ; => clojure.lang.IRecord
(fully-qualified? 'my-var) ; => my-ns/my-var
(fully-qualified? 'alias/my-var) ; => actual.namespace/my-var
fully-qualified?Returns true if the symbol constitutes an absolute reference.
(fully-qualified? 'clojure.lang.IRecord) ; => true
(fully-qualified? 'my-ns/my-var) ; => true
(fully-qualified? 'alias/my-var) ; => false
unqualify(unqualifiy 'clojure.lang.IRecord) ; => IRecord
(unqualifiy 'my-ns/my-var) ; => my-var
(unqualifiy 'alias/my-var) ; => alias/my-var
(unqualifiy 'some.path.Class/staticMeth) ; => Class/staticMeth
with-nsLike in-ns but with the scope of a let or a binding.
(with-ns 'my-namespace ;; or (find-ns 'my-namespace)
(def number 123))
(println my-namespace/number)
;; 123
tree-seq-breadth(let [tree {:a {:d {:j :_}
:e {:k :_}}
:b {:f {:l :_}
:g {:m :_}}
:c {:h {:n :_}
:i {:o :_}}}
keys-only #(->> % (remove #{:_}) (mapcat keys))]
(keys-only (tree-seq map? vals tree))
;; (:a :b :c :d :e :j :k :f :g :l :m :h :i :n :o)
(keys-only (tree-seq-breadth map? vals tree))
;; '(:a :b :c :d :e :f :g :h :i :j :k :l :m :n :o)
)
prepostwalkA combination of clojure.walk's prewalk and postwalk. Recursively modifies form with pre-fn before descending further into the structure and then with post-fn after going up.
(defn inc-it [x]
(if (number? x) (inc x) x))
(defn it-times-two [x]
(if (number? x) (* 2 x) x))
(def data
[1 2 {3 4 5 6}])
(println (prepostwalk inc-it it-times-two data))
;; [4 6 {8 10, 12 14}]
(println (prepostwalk it-times-two inc-it data))
;; [3 5 {7 9, 11 13}]
Comes equipped with prepostwalk-demo.
treeRecursively builds a tree from root and functions
with the following signature:
(children [node]) : returns the direct children of node.(join-branches [node children]): returns a datastructure holding node
and its children.(defn divisors [n]
(tree #(for [m (range 2 %) :let [div (/ % m)] :when (integer? div)]
div)
cons
n))
(divisors 12)
;; => (12 (6 (3) (2)) (4 (2)) (3) (2))
For all features listed below:
(require 'shuriken.dev)
shuriken.monkey-patches.pprint-meta(require 'shuriken.monkey-patches.pprint-meta)
(alter-var-root #'clojure.pprint/*print-meta* (constantly true))
(pprint ^Object ^:flag ^{:meta :yes} [1 2 3])
;; ^Object ^:flag ^{:meta :yes} [1 2 3]
shuriken.monkey-patches.syntax-quoteBefore
``abc
;; (quote my-ns/abc)
(pprint ``abc)
;; 'my-ns/abc
After
(require 'shuriken.monkey-patches.syntax-quote)
``abc
;; (clojure.core/syntax-quote my-ns/abc)
(pprint ``abc)
;; `my-ns/abc
(def args [1 2 3])
(pprint (syntax-quote `(abc ~@args)))
;; `(my-ns/abc 1 2 3)
(pprint (syntax-quote `(abc ~'~@args)))
;; `(my-ns/abc ~@args)
But above all it prevents this:
(pprint ``(do (fn1 arg1 arg2) (fn2 arg3 arg4)))
(clojure.core/seq
(clojure.core/concat
(clojure.core/list 'do)
(clojure.core/list
(clojure.core/seq
(clojure.core/concat
(clojure.core/list 'user/fn1)
(clojure.core/list 'user/arg1)
(clojure.core/list 'user/arg2))))
(clojure.core/list
(clojure.core/seq
(clojure.core/concat
(clojure.core/list 'user/fn2)
(clojure.core/list 'user/arg3)
(clojure.core/list 'user/arg4))))))
And pprints this instead:
(pprint ``(do (fn1 arg1 arg2) (fn2 arg3 arg4)))
`(do (my-ns/fn1 my-ns/arg1 my-ns/arg2) (my-ns/fn2 my-ns/arg3 my-ns/arg4))
Can you improve this documentation?Edit 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 |