← Browse

@unclebob/crap4clj

B

Calculates cyclomatic complexity and CRAP scores for Clojure functions by combining complexity analysis with Cloverage test coverage data, generating sorted reports that identify high-risk under-tested code. Use when the user asks for a CRAP report, cyclomatic complexity analysis, or code quality metrics on a Clojure project.

skillclaude

Install

agr install @unclebob/crap4clj --target claude

Writes 6 files into .claude/skills/, pinned to git-a22525e1.

  • .claude/skills/crap4clj/.gitignore
  • .claude/skills/crap4clj/BUGREPORT-clj-mutate-stale-lcov-and-worker-collision.md
  • .claude/skills/crap4clj/README.md
  • .claude/skills/crap4clj/SKILL.md
  • .claude/skills/crap4clj/bb.edn
  • .claude/skills/crap4clj/deps.edn

Document


name: crap4clj description: "Calculates cyclomatic complexity and CRAP scores for Clojure functions by combining complexity analysis with Cloverage test coverage data, generating sorted reports that identify high-risk under-tested code. Use when the user asks for a CRAP report, cyclomatic complexity analysis, or code quality metrics on a Clojure project."

crap4clj — CRAP Metric for Clojure

Computes the CRAP (Change Risk Anti-Pattern) score for every defn and defn- in a Clojure project. CRAP combines cyclomatic complexity with test coverage to identify functions that are both complex and under-tested.

Setup

Add both a :cov alias (Cloverage) and a :crap alias to the project's deps.edn:

:cov  {:extra-deps {cloverage/cloverage {:mvn/version "1.2.4"}}
       :main-opts ["-m" "speclj.cloverage" "--" "-p" "src" "-s" "spec"]}
:crap {:extra-deps {io.github.unclebob/crap4clj
                     {:git/url "https://github.com/unclebob/crap4clj"
                      :git/sha "<current-sha>"}}
       :main-opts ["-m" "crap4clj.core"]}

The example above uses speclj.cloverage as the runner. For clojure.test projects, use cloverage.coverage instead:

:cov  {:extra-deps {cloverage/cloverage {:mvn/version "1.2.4"}}
       :main-opts ["-m" "cloverage.coverage" "-p" "src" "-s" "test"]}

Adjust the -p (source path) and -s (test path) flags in :cov to match your project layout.

Usage

# First verify Cloverage works on its own
clj -M:cov

# Analyze all source files under src/
clj -M:crap

# Filter to specific modules
clj -M:crap combat movement

crap4clj automatically deletes stale coverage reports, runs clj -M:cov, and then analyzes the results.

Output

A table sorted by CRAP score (worst first):

CRAP Report
===========
Function                       Namespace                            CC   Cov%     CRAP
-------------------------------------------------------------------------------------
complex-fn                     my.namespace                         12   45.0%    130.2
simple-fn                      my.namespace                          1  100.0%      1.0

Interpreting Scores

CRAP ScoreMeaning
1-5Clean — low complexity, well tested
5-30Moderate — consider refactoring or adding tests
30+Crappy — high complexity with poor coverage

How It Works

  1. Deletes old coverage reports and runs Cloverage (clj -M:cov)
  2. Finds all .clj and .cljc files under src/
  3. Extracts defn/defn- functions with line ranges
  4. Computes cyclomatic complexity (if/when/cond/condp/case/cond->/cond->>/some->/some->>/and/or/loop/catch)
  5. Reads Cloverage HTML for per-line form coverage
  6. Applies CRAP formula: CC² × (1 - cov)³ + CC
  7. Sorts by CRAP score descending and prints report

Troubleshooting

  • Cloverage fails to run: Verify :cov alias paths match your project layout — -p should point to your source root and -s to your test root.
  • All coverage shows 0%: Ensure clj -M:cov runs successfully on its own before running :crap. Check that test files are found under the specified test path.
  • Functions show N/A coverage: This occurs with split-file namespace patterns (in-ns + load). Add --lcov to your :cov alias main-opts for accurate per-file coverage.

Trustgrade B

  • passBody integrity

    Whether the stored document is plausibly the kind of file the artifact declares, rather than something fetched by mistake.

  • passType matchnot applicable to this artifact type

    Whether the artifact is really the kind of thing its metadata claims it is.

  • passFreshness

    How long since the source repository was last pushed to.

  • passPrompt injection

    Scans the artifact's own text for instructions aimed at your agent rather than at you.

  • warnLicenseno SPDX license detected

    Whether the source repository declares an SPDX license permissive enough to redistribute.

How the grade is calculated

Each check contributes 0 points when it passes, 1 when it warns, and 2 when it fails. The total maps to a letter:

  • Aevery check passed
  • Bone warning
  • Ctwo warnings
  • Dprompt injection or body integrity failed, or three warnings
  • Fone of those failed, and something else is wrong

These are automated hygiene checks, not a security audit, and not a dependency or vulnerability scan. A grade of A means nothing was flagged — not that the artifact is safe.

Versions

  • git-a22525e1e9682026-07-31