Skip to content
/ blanket Public

Soft encapsulation for Clojure data structures

License

Notifications You must be signed in to change notification settings

vlaaad/blanket

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Blanket Clojars project

Soft encapsulation for Clojure data structures

Rationale

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).

Install

Using git dependency:

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

Using maven:

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

Usage

(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] ,,,)

About

Soft encapsulation for Clojure data structures

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published