Skip to content

Instantly share code, notes, and snippets.

@lagenorhynque
Last active November 11, 2022 07:15
Show Gist options
  • Select an option

  • Save lagenorhynque/8f301090b33f0668a061a7fd4072b18e to your computer and use it in GitHub Desktop.

Select an option

Save lagenorhynque/8f301090b33f0668a061a7fd4072b18e to your computer and use it in GitHub Desktop.
Clojure Linters

Clojure Linters


Self-introduction

lagénorhynque /laʒenɔʁɛ̃k/ カマイルカ

(defprofile lagénorhynque
  :name         "Kent OHASHI"

  :languages    [Clojure Haskell Python Scala
                 English français Deutsch русский]

  :interests    [programming language-learning mathematics]

  :contributing [github.com/japan-clojurians/clojure-site-ja])

twitter icon


Clojure product introduction


  1. cljfmt: formatter

  2. eastwood: linter

  3. kibit: idiom checker

  4. Example Usage

  5. Other Tools


formatter


What's the problem?

(when something
  (something-else)
)

$ lein cljfmt check
 (when something
-  (something-else)
-)
+  (something-else))

What's the problem?

(when something
    something-else)

$ lein cljfmt check
 (when something
-    something-else)
+  something-else)

What's the problem?

(filter even?
  (range 1 10))

$ lein cljfmt check
 (filter even?
-  (range 1 10))
+        (range 1 10))

What's the problem?

(if something
    ala
    bala)

$ lein cljfmt check
 (if something
-    ala
-    bala)
+  ala
+  bala)

What's the problem?

(or
  ala
  bala
  portokala)

$ lein cljfmt check
 (or
-  ala
-  bala
-  portokala)
+ ala
+ bala
+ portokala)

linter


What's the problem?

(ns linting-example.eastwood-target
  (:use [clojure.string]))

$ lein eastwood
src/linting_example/eastwood_target.clj:2:10: unlimited-use: Unl
imited use of ([clojure.string]) in linting-example.eastwood-tar
get

What's the problem?

(if-let [x []]
  (conj x 42)
  :falsy)

$ lein eastwood
src/linting_example/eastwood_target.clj:4:1: constant-test: Test
expression is always logical true or always logical false: [] in
form (if temp__5455__auto__ (clojure.core/let [x temp__5455__aut
o__] (conj x 42)) :falsy)

What's the problem?

(defn f [x]
  (def y (* x x))
  (+ y 2))

$ lein eastwood
src/linting_example/eastwood_target.clj:9:8: def-in-def: There i
s a def of y nested inside def f

What's the problem?

(defn g [x]
  "blah blah blah."
  (* x x))

$ lein eastwood
src/linting_example/eastwood_target.clj:12:7: misplaced-docstrin
gs: Possibly misplaced docstring, g
src/linting_example/eastwood_target.clj:12:1: unused-ret-vals: C
onstant value is discarded: "blah blah blah."

What's the problem?

(defn h [str]
  (str "Hello, " str "!"))

$ lein eastwood
src/linting_example/eastwood_target.clj:17:3: local-shadows-var:
local: str invoked as function shadows var: #'clojure.core/str

idiom checker


What's the problem?

(defn add-one [x]
  (+ x 1))

$ lein kibit
At src/linting_example/kibit_target.clj:4:
Consider using:
  (inc x)
instead of:
  (+ x 1)

What's the problem?

(defn check-if-zero? [x]
  (== x 0))

$ lein kibit
At src/linting_example/kibit_target.clj:7:
Consider using:
  (zero? x)
instead of:
  (== x 0)

What's the problem?

(defn zip-with-* [xs ys]
  (map #(* %1 %2) xs ys))

$ lein kibit
At src/linting_example/kibit_target.clj:null:
Consider using:
  *
instead of:
  #(* %1 %2)

What's the problem?

(defn coll->vec [coll]
  (into [] coll))

$ lein kibit
At src/linting_example/kibit_target.clj:13:
Consider using:
  (vec coll)
instead of:
  (into [] coll)

What's the problem?

(defn flat-map [f coll]
  (apply concat (map f coll)))

$ lein kibit
At src/linting_example/kibit_target.clj:16:
Consider using:
  (mapcat f coll)
instead of:
  (apply concat (map f coll))

Example Usage


e.g. lagenorhynque/situated-program-challenge/rest-server/project.clj

:plugins [[jonase/eastwood "0.2.5"]
          [lein-cljfmt "0.5.7"]
          [lein-kibit "0.1.6"]]
:aliases {"lint" ^{:doc "Execute cljfmt check, eastwood and kibit."}
          ["do" ["cljfmt" "check"]
                ["eastwood" "{:source-paths [\"src\"]}"]
                ["kibit"]]}

↓↓↓

  lein cljfmt check && lein eastwood <opts> && lein kibit
= lein do cljfmt check, eastwood <opts>, kibit
= lein lint  # alias as `lint`

$ lein lint
All source files formatted correctly
== Eastwood 0.2.5 Clojure 1.9.0 JVM 9.0.1
Directories scanned for source files:
  src test
== Linting rest-server.util ==
== Linting rest-server.boundary.db.core ==
== Linting rest-server.boundary.db.group ==
...
== Linting rest-server.handler.venue-test ==
== Linting rest-server.handler.meetup-test ==
== Linting rest-server.handler.member-test ==
== Warnings: 0 (not including reflection warnings)
  Exceptions thrown: 0

Other Tools


dependency


namespace


dead code


vulnerability


test coverage


misc.


Utilise linters for clean Clojure code!

Lisp Alien


Further Reading

#!/usr/bin/env bash
# npm install -g reveal-md
reveal-md clojure-linters.md --theme night --highlight-theme monokai-sublime $@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment