Skip to content
Soft encapsulation for Clojure data structures
Clojure Shell
Branch: master
Clone or download
vlaaad Merge pull request #1 from martinklepsch/patch-1
fix typo in deps.edn coordinates
Latest commit c41fa87 Sep 6, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
src/blanket Add print-as, simplify README Sep 6, 2019
test/blanket Add print-as, simplify README Sep 6, 2019
.gitignore Initial commit Sep 6, 2019
LICENSE Initial commit Sep 6, 2019
deps.edn Initial commit Sep 6, 2019
pom.xml Release 1.1.0 Sep 6, 2019 Initial commit Sep 6, 2019

Blanket Clojars project

Soft encapsulation for Clojure data structures


There is value in hiding data even when it's immutable: drawing a line between public API and implementation details. You might want to create a library (or module in an application) that allows it's users to create some entity and then pass it back to you to other functions. It creates a problem: users might start using internals of returned data structure, even though they are not intended to be used. You still want to be able to change shape of this data in the future without breaking your users' code, so you write in your documentation that shape of your entity is internal and subject to change, hoping that people will read and remember it... And this is where Blanket steps in: it shows users of your library — at the REPL — that part of what you give them is implementation details.

Blanket is extremely lightweight and non-intrusive: it changes covered objects' metadata to only affect printing, so your covered hash-map is still the same hash-map, and your covered vector is still the same vector, with all equality semantics etc. retained. It does not really prevent any access, just helps your users to get better understanding of your library's API contracts (hence soft encapsulation).


Using git dependency:

com.github.vlaaad/blanket {:git/url ""
                           :sha "3f54f3cfec43f9de67cda56cc2ec1d88d7936951"}

Using maven:

com.github.vlaaad/blanket {:mvn/version "1.1.0"}


(ns service
  (:require [blanket.core :as blanket]))

;; mark data structure as namespace-local, optionally set how it's printed
(def async-config
  (blanket/cover {:async true} :print-method (blanket/print-as 'async-config)))

;; in same namespace, you'll still see it
(prn async-config) 
=> {:async true}
;; in other namespace, you wont see it
(in-ns 'service-user)
(clojure.core/prn service/async-config) 
=> #impl[service async-config]
(in-ns 'service)

(defn make [opts]
  ;; Since `make` can be called from other namespace, we should specify 
  ;; encapsulation namespace directly (*ns* will be different)
  (blanket/cover {:opts opts} :ns 'service))

(in-ns 'service-user)
(clojure.core/prn (service/make {:some :opts})) ;; => #impl[service 0x7c6442c2]
(in-ns 'service)

;; here goes remaining API...
(defn perform-request [service config] ,,,)
You can’t perform that action at this time.