1 Introduction
1.1 Overview
std.lib.env provides environment and system utilities including:
- Namespace introspection
- Resource management
- Development helpers
- Pretty printing utilities
- Debug facilities
2 Walkthrough
2.1 Namespace and resource introspection
std.lib.env provides helpers for inspecting the current namespace and locating classpath resources.
inspect the current namespace and resources
^{:refer std.lib.env/ns-sym :added "3.0"}
(ns-sym)
=> 'documentation.std-lib-env
^{:refer std.lib.env/sys:resource :added "3.0"}
(sys:resource "std/lib.clj")
=> java.net.URL
^{:refer std.lib.env/sys:ns-url :added "4.0"}
(sys:ns-url 'std.lib.env)
=> java.net.URL
2.2 Local function overrides
local:set and local allow you to override functions like println within a scope. p is a shortcut for the local println.
override and call a local function
^{:refer std.lib.env/local:set :added "3.0"}
(local:set :test (fn [] :hello))
=> map?
^{:refer std.lib.env/local :added "3.0"}
(local :test)
=> :hello
^{:refer std.lib.env/p :added "3.0"}
(with-out-str (p "hello"))
=> "hello\n"
2.3 Pretty printing
pp-str returns a pretty-printed string, and pp writes it to the local pprint output.
pretty print values
^{:refer std.lib.env/pp-str :added "4.0"}
(pp-str {:a 1})
=> "{:a 1}"
^{:refer std.lib.env/pp :added "3.0"}
(with-out-str (pp {:a 1}))
=> string?
3 Namespace Utilities
v 3.0
(defn dev?
([]
(-> (try
(the-ns 'nrepl.core)
(catch Exception e))
boolean)))
link
(dev?) => boolean?
v 3.0
(defn ns-get
([sym]
(ns-get clojure.core/*ns* sym))
([ns k]
(let [elem (resolve (symbol (str ns) (str k)))]
(if elem
@elem
(ex-info (format "Cannot find %s in namespace" k)
{:ns ns})))))
link
(ns-get 'std.lib.env "ns-get") => fn?
4 Resource Management
v 4.0
(defn sys:ns-dir
([]
(sys:ns-dir (.getName *ns*)))
([ns]
(-> (.getFile (sys:ns-url ns))
(java.io.File.)
(.getParent))))
link
(sys:ns-dir 'std.lib.env) => string?
v 4.0
(defn sys:ns-file
([]
(sys:ns-file (.getName *ns*)))
([ns]
(-> (.getFile (sys:ns-url ns))
(java.io.File.)
(str))))
link
(sys:ns-file 'std.lib.env) => string?
v 4.0
(defn ^java.net.URL sys:ns-url
([]
(sys:ns-url (.getName *ns*)))
([ns]
(-> (name ns)
(.replace - _)
(.replace . /)
(str ".clj")
(sys:resource))))
link
(sys:ns-url 'std.lib.env) => java.net.URL
v 3.0
(defn ^java.net.URL sys:resource
([n] (sys:resource n (.getContextClassLoader (Thread/currentThread))))
([n ^ClassLoader loader] (.getResource loader n)))
link
(sys:resource "std/lib.clj") => java.net.URL
v 4.0
(defn sys:resource-cached
[atom path f]
(let [url (sys:resource path)
fpath (.getFile url)
t (if fpath (.lastModified (java.io.File. fpath)))]
(cond (not t)
(f url)
:else
(at/swap-return! atom
(fn [m]
(let [{:keys [time content]} (get m path)]
(if (= time t)
[content m]
(let [content (f url)]
[content (assoc m path {:time t :content content})]))))))))
link
(sys:resource-cached (atom {}) "scratch.clj" slurp) => string?
5 Pretty Printing
v 3.0
(defmacro pl
([body]
(with-meta `(pl ~body nil) (meta &form)))
([body range]
(let [{:keys [line column]} (meta &form)]
`(do (local :println (format "%s (%d:%d)"
~(str (ns-sym))
~line
~column))
(local :println
(pl-add-lines (with-out-str (print ~body))
~range)
"n")))))
link
(with-out-str (pl "hello")) => string?
v 4.0
(defn pp-fn
([& body]
(doseq [v body]
(p (pp-str v) "n"))))
link
(with-out-str (pp-fn {:a 1})) => (any string? nil?)
v 4.0
(defn pp-str
[& args]
(clojure.string/join "n" (map #(local :pprint-str %) args)))
link
(pp-str {:a 1}) => "{:a 1}"
6 Debug Utilities
v 4.0
(defn dbg-global
([] *debug*)
([flag]
(alter-var-root #'*debug* (fn [_] flag))))
link
(dbg-global) => boolean?
dbg-print ^
[ns-str {:keys [line column]} & args]
prints debug info with namespace and location
v 4.0
(defn dbg-print
[ns-str {:keys [line column]} & args]
(when (or *debug*
(some (fn [filt]
(match-filter filt ns-str))
(seq @+debug+)))
(local :println (format "%s (%d:%d)"
ns-str
line
column))
(doseq [arg args]
(local :pprint arg))))
link
(with-out-str (dbg-print "hello" {:line 1 :column 1} "world")) => string?
v 4.0
(defn dbg:add-filters
([& filters]
(swap! +debug+
(fn [coll] (apply conj coll filters)))))
link
(dbg:add-filters :test) => set?
7 Local State
8 Error Handling
9 std.lib.env: A Comprehensive Summary
The std.lib.env namespace provides a collection of utility functions and macros for interacting with the Clojure runtime environment, managing resources, and enhancing debugging and logging capabilities. It offers tools for namespace introspection, class path resource loading, dynamic function binding, and advanced printing/metering.
Key Features and Concepts:
- Namespace and Symbol Utilities:n
ns-sym []: Returns the symbol representing the current namespace.nns-get [ns k]: Resolves and returns the value of a symbolkwithin a given namespacens.nrequire [sym]: A concurrency-safe wrapper aroundclojure.core/require.nn2. Environment Detection:ndev? []: Checks if the current environment is a development environment (by looking fornrepl.core).nn3. Class Path Resource Management:nsys:resource [n & [loader]]: Finds a resourcenon the class path, returning itsjava.net.URL.nsys:resource-cached [atom path f]: Caches the result of applying a functionfto a class path resourcepath, invalidating the cache if the resource's modification time changes.nsys:resource-content [path]: Reads and caches the content of a class path resource as a string.nsys:ns-url [& [ns]]: Gets thejava.net.URLfor a given namespace (or the current one).nsys:ns-file [& [ns]]: Gets the file path for a given namespace.nsys:ns-dir [& [ns]]: Gets the directory path for a given namespace.nn4. Resource Management:nclose [obj]: Closes any object implementingjava.io.Closeable.nn5. Local Function Overrides:n*local*: A dynamic var controlling whether local function overrides are active.n+local+: An atom holding a map of locally overridden functions (e.g.,println,prn,pprint).nlocal:set [k v & more]: Sets or updates local function overrides in+local+.nlocal:clear [k & more]: Clears local function overrides from+local+.nlocal [k & args]: Applies the locally overridden function associated with keyk.nn6. Enhanced Printing and Debugging:np [& args]: Shortcut for(local :println).npp-str [& args]: Pretty-prints arguments to a string.npp-fn [& body]: A function that pretty-prints its arguments.npp [& body]: A macro that pretty-prints its arguments, including namespace, line, and column information.ndo:pp [v]: Adoto-like macro forpp.npl-add-lines [body & [range pad]]: Helper forpl, adds line numbers to a string.npl [body & [range]]: A macro that printsbodywith line numbers, including namespace, line, and column information.ndo:pl [v]: Adoto-like macro forpl.npl:fn []: Creates a function that prints with line numbers.nprn [& body]: A macro that prints its arguments (likeclojure.core/prn), but also includes namespace, line, and column information.ndo:prn [& args]: Adoto-like macro forprn.nprn:fn []: Creates a function that prints with namespace and file info.nprf [v & [no-pad]]: Pretty-prints with optional padding.nmeter [label & body]: A macro that measures and prints the time taken to execute a code block, including namespace, line, and column information.nmeter-out [& body]: Measures and returns the time taken and the result of a code block.nthrowable-string [t]: Converts aThrowableinto a stack trace string.nexplode [& body]: A macro that executes a body, catches anyThrowable, and prints its stack trace with context information.nn7. Conditional Debugging (dbg):n*debug*: A dynamic var to globally enable/disabledbgoutput.n+debug+: An atom holding a set of filters (regex, string, symbol, function) to selectively enabledbgoutput for specific namespaces or symbols.nmatch-filter [filt id]: A helper function to check if anidmatches a given filter.ndbg-print [ns-str meta & args]: The underlying function fordbg, which prints debug information if*debug*is true or if the namespace matches a filter.ndbg [& body]: A macro for conditional debugging output. It prints arguments along with source location if debugging is enabled globally or for the current namespace.nwith:dbg [flag & body]: A macro to temporarily bind*debug*for a block of code.ndbg-global [& [flag]]: Getter/setter for the global*debug*flag.ndbg:add-filters [& filters]: Adds filters to+debug+to enable selective debugging.ndbg:remove-filters [& filters]: Removes filters from+debug+.
Overall Importance:
The std.lib.env module is a crucial utility for developers working within the foundation-base project. It provides:
- Enhanced Development Workflow: Tools like
pp,pl,prn,meter, anddbgsignificantly improve the debugging and introspection experience, offering more context-rich output than standard Clojure functions.n Resource Management: Functions for loading and caching class path resources are essential for managing application assets and configurations.n Dynamic Environment Control: The ability to override local functions and control debugging output dynamically allows for flexible adaptation to different development and production needs.n* Robust Error Reporting:explodeandthrowable-stringprovide better visibility into exceptions, aiding in faster bug resolution.
By offering these comprehensive environment and debugging utilities, std.lib.env contributes significantly to the productivity and maintainability of the foundation-base codebase.