Skip to content

Commit

Permalink
Write up the rationale
Browse files Browse the repository at this point in the history
  • Loading branch information
plexus committed Feb 24, 2021
1 parent e8ceb48 commit f141c9c
Showing 1 changed file with 84 additions and 7 deletions.
91 changes: 84 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
# lambdaisland/data-printers

<!-- badges -->
[![CircleCI](https://circleci.com/gh/lambdaisland/.svg?style=svg)](https://circleci.com/gh/lambdaisland/) [![cljdoc badge](https://cljdoc.org/badge/lambdaisland/)](https://cljdoc.org/d/lambdaisland/) [![Clojars Project](https://img.shields.io/clojars/v/lambdaisland/.svg)](https://clojars.org/lambdaisland/)
[![CircleCI](https://circleci.com/gh/lambdaisland/data-printers.svg?style=svg)](https://circleci.com/gh/lambdaisland/data-printers) [![cljdoc badge](https://cljdoc.org/badge/lambdaisland/data-printers)](https://cljdoc.org/d/lambdaisland/data-printers) [![Clojars Project](https://img.shields.io/clojars/v/lambdaisland/data-printers.svg)](https://clojars.org/lambdaisland/data-printers)
<!-- /badges -->

Quickly define print handlers for tagged literals across print/pprint implementations.
Expand All @@ -16,7 +16,7 @@ Quickly define print handlers for tagged literals across print/pprint implementa

## Support Lambda Island Open Source

is part of a growing collection of quality Clojure libraries and
data-printers is part of a growing collection of quality Clojure libraries and
tools released on the Lambda Island label. If you are using this project
commercially then you are expected to pay it forward by
[becoming a backer on Open Collective](http://opencollective.com/lambda-island#section-contribute),
Expand All @@ -30,29 +30,106 @@ so that we may continue to enjoy a thriving Clojure ecosystem.

## Features

One stop shop registration of print handlers

- print-method
- print-dup
- clojure.pprint

<!-- installation -->
## Installation

deps.edn

```
lambdaisland/ {:mvn/version "0.0.0"}
lambdaisland/data-printers {:mvn/version "0.0.0"}
```

project.clj

```
[lambdaisland/ "0.0.0"]
[lambdaisland/data-printers "0.0.0"]
```
<!-- /installation -->

## Rationale

With Clojure/ClojureScript we get a serialization format for free, out of the
box. [EDN](https://github.com/edn-format/edn) or Extensible Data Notation is a
subset of the Clojure syntax format, which can represent all of Clojure's
built-in primitives and collections.

In LISP parlance serializing data is called "printing", and deserializing is
referred to as "reading".

``` clojure
(pr-str {:x 1 :y 2})
;;=> "{:x 1 :y 2}"

(read-string "{:x 1 :y 2}")
;;=> {:x 1 :y 2}
```

Types that are not native to Clojure however will throw a spanner in the works.
They will print in a way that is noisy and opaque, and what is worse: this
printed version is no longer valid EDN. It will file to be read back.

``` clojure
(deftype CustomType [x])

(pr-str (->CustomType 1))
;; => "#object[my.ns.CustomType 0x49763a36 \"my.ns.CustomType@49763a36\"]"

(read-string "#object[my.ns.CustomType 0x49763a36 \"my.ns.CustomType@49763a36\"]")
;; java.lang.RuntimeException
;; No reader function for tag object
```

To solve this EDN provides tagged literals, for instance the value
`(->CustomType 1)` could be represented as `#my.ns/CustomType {:x 1}`. Now this
is valid EDN, and you get to see what you are dealing with. For a REPL-based
workflow, or when wading through test results being able to see the actual
values is invaluable. (pun intended) To make this work you need to teach both
the reader and the printer about the tag and the type.

Dealing with the reader is relatively straightforward, you do this by supplying
a `data_readers.cljc`, or by binding `*data-readers*`, see the [Tagged
Literals](https://clojure.org/reference/reader#tagged_literals) section in the
official Clojure docs.

When it comes to printing however the situation is more complex. There are
multiple printer implementations, and significant differences between Clojure
and ClojureScript. This is where this library comes in. It aims to make it easy
to define print handlers, and to have them set up across implementations, so you
always get consistent results.

Clojure and ClojureScript contain two built-in printers, the one that powers all
the `pr` functions (`pr`, `prn`, `pr-str`, etc), and `clojure.pprint`. On the
Clojure side you need to extend multimethods, for ClojureScript you implement a
protocol. We pave over these differences by providing a number of functions all
with the same signature.

``` clojure
(register-print CustomType 'my.ns/CustomType (fn [obj] {:x (.-x obj)}))
```

This takes the type (`java.lang.Class` or JavaScript constructor function), a
tag as a symbol, and a function returning a plain EDN representation of
instances of the type.

Available functions:

```
lambdaisland.data-printers/register-print
lambdaisland.data-printers/register-pprint
```

## Usage

<!-- contributing -->
## Contributing

Everyone has a right to submit patches to , and thus become a contributor.
Everyone has a right to submit patches to data-printers, and thus become a contributor.

Contributors MUST

Expand Down Expand Up @@ -87,4 +164,4 @@ changes are justified.
Copyright &copy; 2021 Arne Brasseur and Contributors

Licensed under the term of the Mozilla Public License 2.0, see LICENSE.
<!-- /license -->
<!-- /license -->

0 comments on commit f141c9c

Please sign in to comment.