Clojure snippets

2 minute read

I’m planning to build a proper clojure snippets/cheat-sheet page, for all the things I do regularly, or want to encourage team members to do regularly. But it’s easier to blog these to get them out rapidly, I’ll try to format them nicely later.

Namespaces and main methods

(ns foo.bar
  (:import [java.net URI URL])
  (:require [clj-http.client :as client :refer [request]]
            [compojure.core :refer :all]) ; prefer this over 'use'
  (:gen-class))  ; if you have a main method to expose

(defn -main
  [& args]
  (println "args:" args))

Midje basics

(ns foo.t-bar
  (:require [midje.sweet :refer :all]
            [foo.bar :as subject]))  ; or just :refer :all

(facts "about foos"
  (fact "the foo is alive"
    (subject/foo 123) => (just {:foo 123})
    (provided (bar 123) => :foo)))

Midje custom checker

(defn same-json [expected]
  (fn [actual]
    (= (parse-string actual true) (parse-string expected true))))

; or the same test but better outputs on failure

(defchecker same-json [expected]
  (chatty-checker [actual]
     (= (parse-string actual true) (parse-string expected true))))

(fact "json is similar"
  (slurp "file1.json") => (same-json (slurp "file2.json")))

Destructuring

(let [[a b & rest :as all]       [:a :b :c :d]
      {e :e [f g] :fg}           {:e "e" :fg ["f" "g"]}
      {:keys [h i] :or {:h "h"}} {:i "i"}]
      ; a is :a, b is :b, e is "e", f is "f", g is "g"
      ; h defaults to "h", i is "i"
      ; rest is [:c :d]
      ; all is [:a :b :c :d]
)

(for [[key val] {:a "a" :b "b" :c "c"} ... )

; mostly avoid this as the syntax is confusing, but on occasion:
(defn foo [& {:keys [a b] :or {a "foo" b "bar"}]
  (println a b))

; special syntax for passing key/val parameters:
(foo :b "baz") => "foo baz"

Map manipulation

(def old-map {:foo :bar, :baz :bat})
(into {}
  (for [[k v] old-map]
    [v k]))  ; or anything that produces a pair
=> {:bar :foo, :bat :baz}

see also https://github.com/clojure/algo.generic if you just want to manipulate values not keys

Protocols and Records

(defprotocol FooBar
  (buzz [this] "does a buzzy thing"))

(defrecord Widget [hands feet]
  FooBar
  (buzz [this] (str hands feet)))

(buzz (Widget. "ha" "fe"))
=> "hafe"

; same as above but '->Widget' is a first class function
(buzz (->Widget "h" "f"))
=> "hf"

(buzz (map->Widget {:feet "foot"}))
=> "foot"  ; hands is nil

(extend-type Integer
  FooBar
  (buzz [this] (str "buzz:" this)))

(buzz 17)
=> "buzz:17"

Threading

(-> x y (z :a) foo)
; same as
(foo (z (y x) :a))

(->> x y (z :a) foo)
; same as
(foo (z :a (y x)))

; need to wrap anonymous fns:
(-> x (#(reverse %)) y)
; same as
(y (#(reverse %) x))

(as-> foo x
      (inc x)
      (* x 3))
; same as
(* (inc foo) 3)

; also can nest as-> inside ->
(-> foo
    inc
    (as-> x
       (foo x bar)
       (baz x)))

Paredit and Cursive

I’ve mostly moved from emacs to Intellij Idea + the Cursive plugin

I intend to put up a decent cheat sheet for using Cursive’s structural mode, which is basically a variant of paredit. But I’m out of time. For now, look at the excellent tutorial on the cursive site.

Comments