Debux Documentation

repository·master·Indexed 19 days ago

https://github.com/philoskim/debux

A debugging library for Clojure and ClojureScript that provides deep visibility into expression evaluation, thread macros, and data transformations. Features include the `dbg` and `clog` macros for REPL and browser console output, `break` for setting breakpoints, and specialized tools like `dbgt` and `clogt` for debugging transducers. It supports tagged literals, dynamic messages, and provides a `debux-stubs` version for production to ensure zero runtime overhead.

Tokens
7.3K
Snippets
34
Records
50
Agent score
67%

What's inside Debux

  1. Debug `let` and `comp` forms

    master

    The dbg macro provides visibility into binding forms and function compositions:

    • let forms: Prints every binding in the let block.
    • comp forms: Prints the result of each function in the composition chain.
    ;; Debugging let
    (dbg (let [a (take 5 (range)) 
               {:keys [b c d] :or {d 10 b 20 c 30}} {:c 50 :d 100}] 
            [a b c d]))
    
    ;; Debugging comp
    (def c (dbg (comp inc inc +)))
    (c 10 20) ; Prints intermediate steps
  2. Use debux macros in Node.js

    master

    When running ClojureScript on Node.js, use dbg and dbgn instead of clog and clogn. This is because the Node.js console.log does not support colors, whereas dbg macros are optimized for the Node.js environment.

    However, if you are developing for Electron, you should use clog and clogn because Electron's console supports colors.

    (ns examples.node
      (:require [cljs.nodejs :as nodejs]
                [debux.cs.core :refer-macros [clog clogn dbg dbgn]] ))
    
    (defn -main [& args]
      (dbgn (+ 2 (* 3 4)))
      (clogn (+ 2 (* 3 4))))
    
    (set! *main-cli-fn* -main)
  3. Use debux.el for Emacs CIDER

    master

    The debux.el script provides helper functions for Emacs CIDER users to quickly insert or delete debugging macros.

    Installation

    Append debux.el (found in the project root) to your ~/.emacs.d/init.el.

    Usage

    • For .clj or .cljc files: Use dbg or dbgn.
    • For .cljs files: Use clog or clogn.

    Inserting Macros

    • Double-click an open parenthesis: If the parenthesis does not already contain a debux macro, the script will wrap the expression in (dbg ...) or (clog ...).
    • Double-click a symbol: Inserts the macro around the symbol (e.g., (+ a b) becomes (+ (dbg a) b)).
    • Ctrl + Double-click an open parenthesis: Inserts the 'n' version (e.g., (dbgn ...) or (clogn ...)) to wrap entire forms like defn.

    Deleting Macros

    • Double-click an open parenthesis: If the parenthesis contains a debux macro (e.g., (dbg ...)), the script will remove the macro and leave the inner expression.
  4. Install Debux for development and production

    master

    Debux provides two separate libraries to ensure zero runtime/compile-time cost in production while providing full debugging capabilities in development.

    1. In Development: Use philoskim/debux. This library emits debugging messages to the REPL or browser console.
    2. In Production: Use philoskim/debux-stubs. This library has the same public API, but the macros expand to the original form itself, imposing no overhead.

    WARNING: Never use philoskim/debux in production, as it imposes significant performance overhead even if (set-debug-mode! false) is called.

    ;; In project.clj (Development)
    [philoskim/debux "0.9.1"]
    
    ;; In project.clj (Production)
    [philoskim/debux-stubs "0.9.1"]
  5. Debug thread macros with `dbg`

    master

    The dbg macro has special support for threading macros:

    1. Outside thread macros: When wrapping a thread macro (e.g., -> or ->>), dbg automatically prints every expression within the thread.
    2. Inside thread macros: To debug a specific step within a thread macro, place dbg after the expression you want to inspect.

    Note: Do not attempt to wrap a step inside the thread macro like (-> x (dbg (get :a)) (y)), as this will cause exceptions. Instead, use (-> x (get :a) dbg (y)).

    dbg also supports some->, some->>, cond->, and cond->>.

    ;; Debugging thread-first (->)
    (dbg (-> "a b c d"
             .toUpperCase
             (.replace "A" "X")
             (.split " ")
             first))
    
    ;; Debugging a specific step inside a thread macro
    (-> {:a [1 2]}
        (get :a)
        dbg
        (conj 3))
    
    ;; Debugging thread-last (->>)
    (dbg (->> c (+ 3) (/ 2) (- 1)))
    
    ;; Debugging cond->
    (dbg (cond-> a
           (even? a) inc
           (= a 20) (* 42)))
  6. Use `dbg-last` and `clog-last` inside thread-last macros

    master

    When using the thread-last macro ->>, the standard dbg macro can cause errors because it expects to return a collection for the next step, but might return a non-collection type. Use dbg-last (Clojure) or clog-last (ClojureScript) to safely inspect values within a ->> pipeline.

    (->> (range 20)
         (filter odd?)
         (dbg-last 5 "after filter")
         (map inc))
  7. Use `dbg` and `dbgn` for basic debugging

    master

    Debux provides macros to inspect values during execution.

    • dbg: Evaluates a form and prints the result along with the form itself.
    • dbgn: Similar to dbg, but designed to show the step-by-step evaluation of nested forms, making it ideal for inspecting complex expressions or thread-first/thread-last macros.

    Example of dbgn showing nested evaluation:

    (dbgn (+ 10 (mul 2 3)))
    ; => 
    ; | 10 => 10
    ; | (mul 2 3) => 6
    ; | (+ 10 6) => 16
    (dbgn (+ 10 (mul 2 3)))
  8. Debug transducers with `dbgt` and `clogt`

    master

    Use dbgt (Clojure) or clogt (ClojureScript) to debug transducers. These macros show the input (|>) and output (|<) of each step in a transducer composition.

    ;; Debugging a single transducer
    (transduce (dbgt (filter odd?)) conj (range 5))
    
    ;; Debugging composed transducers
    (transduce (dbgt (comp (map inc) (filter odd?))) conj (range 5))
    (transduce (dbgt (comp (map inc) (filter odd?))) conj (range 5))