Skip to content

Commit 67d1ebf

Browse files
authored
Merge pull request #35 from lambdaisland/arne/custom-types-readme
Expand README regarding custom types
2 parents 3f5cf32 + 5d28de4 commit 67d1ebf

File tree

2 files changed

+118
-7
lines changed

2 files changed

+118
-7
lines changed

README.md

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,28 +88,73 @@ For fine grained control you can create a custom Puget printer, and supply it to
8888

8989
For more advanced uses like incorporating diffs into your own Fipp documents, see `lambdaisland.deep-diff2.printer/format-doc`, `lambdaisland.deep-diff2.printer/print-doc`.
9090

91-
You can register print handlers for new types using
92-
`lambdaisland.deep-diff2.printer/register-print-handler!`, or by passing and
91+
### Print handlers for custom or built-in types
92+
93+
In recent versions deep-diff2 initializes its internal copy of Puget with
94+
`{:print-fallback :print}`, meaning it will fall back to using the system
95+
printer, which you can extend by extending the `print-method` multimethod.
96+
97+
This also means that we automatically pick up additional handlers installed by
98+
libraries, such as [time-literals](https://github.com/henryw374/time-literals).
99+
100+
You can also register print handlers for deep-diff2 specifically by using
101+
`lambdaisland.deep-diff2.printer-impl/register-print-handler!`, or by passing an
93102
`:extra-handlers` map to `printer`.
94103

95-
Note: the default printer is initialized as `(ddiff/printer {:print-fallback :print})` so that it will fall back to system printer when there is no match.
104+
If you are dealing with printing of custom types you might find that there are
105+
multiple print implementations you need to keep up-to-date, see
106+
[lambdaisland.data-printers](https://github.com/lambdaisland/data-printers) for
107+
a high-level API that can work with all the commonly used print implementations.
108+
109+
#### Example of a custom type
110+
111+
See [repl_sessions/custom_type.clj](repl_sessions/custom_type.clj) for the full
112+
code and results.
113+
114+
```clj
115+
(deftype Degrees [amount unit]
116+
Object
117+
(equals [this that]
118+
(and (instance? Degrees that)
119+
(= amount (.-amount that))
120+
(= unit (.-unit that)))))
121+
122+
;; Using system handler fallback
123+
(defmethod print-method Degrees [degrees out]
124+
(.write out (str (.-amount degrees) "°" (.-unit degrees))))
125+
126+
;; OR Using a Puget-specific handler
127+
(lambdaisland.deep-diff2.printer-impl/register-print-handler!
128+
`Degrees
129+
(fn [printer value]
130+
[:span
131+
(lambdaisland.deep-diff2.puget.color/document printer :number (str (.-amount value)))
132+
(lambdaisland.deep-diff2.puget.color/document printer :tag "°")
133+
(lambdaisland.deep-diff2.puget.color/document printer :keyword (str (.-unit value)))]))
134+
```
96135

97136
### Time, data literal
98137

99-
One of the creative ways of using deep-diff is to diff two time data.
138+
A common use case is diffing and printing Java date and time objects
139+
(`java.util.Date`, `java.time.*`, `java.sql.Date|Time|DateTime`).
100140

101-
```
141+
Chances are you already have print handlers (and data readers) set up for these
142+
via the [time-literals](https://github.com/henryw374/time-literals) library
143+
(perhaps indirectly by pulling in [tick](https://github.com/juxt/tick). In that
144+
case these should _just work_.
145+
146+
```clj
102147
(ddiff/diff #inst "2019-04-09T14:57:46.128-00:00"
103148
#inst "2019-04-10T14:57:46.128-00:00")
104149
```
105150
or
106-
```
151+
```clj
107152
(import '[java.sql Timestamp])
108153
(ddiff/diff (Timestamp. 0)
109154
(doto (Timestamp. 1000) (.setNanos 101)))
110155
```
111156

112-
If you need to diff a rich set of time literal, using [time-literals](https://github.com/henryw374/time-literals) is probably a good choice.
157+
If you need to diff a rich set of time literal, using
113158

114159
```
115160
(require '[time-literals.read-write])
@@ -125,6 +170,13 @@ code to CLJC we were forced to make some breaking changes. To not break existing
125170
consumers we decided to move both the namespaces and the released artifact to
126171
new names, so the old and new deep-diff can exist side by side.
127172

173+
We also had to fork Puget to make it cljc compatible. This required breaking
174+
changes as well, making it unlikely these changes will make it upstream, so
175+
instead we vendor our own copy of Puget under `lambdaisland.deep-diff2.puget.*`.
176+
This does mean we don't automatically pick up custom Puget print handlers,
177+
unless they are *also* registered with our own copy of Puget. See above for more
178+
info on that.
179+
128180
When starting new projects you should use `lambdaisland/deep-diff2`. However if
129181
you have existing code that uses `lambdaisland/deep-diff` and you don't need the
130182
ClojureScript support then it is not necessary to upgrade. The old version still

repl_sessions/custom_types.clj

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
(ns repl-sessions.custom-types
2+
(:require [lambdaisland.deep-diff2 :as ddiff]))
3+
4+
;; Demonstration of how to set up print handlers for custom types.
5+
6+
;; New custom type for reprsenting "degrees" amount, like Celcius or Fahrenheit.
7+
;; Using `deftype` and not `defrecord` because we handle `defrecord` instances
8+
;; already as if they are maps.
9+
10+
(deftype Degrees [amount unit]
11+
Object
12+
(equals [this that] ; needed for proper diffing
13+
(and (instance? Degrees that)
14+
(= amount (.-amount that))
15+
(= unit (.-unit that)))))
16+
17+
;; No custom handler yet, defaults to Object#toString rendering:
18+
19+
(pr-str (->Degrees 10 "C"))
20+
;; => "#object[custom_types.Degrees 0x75634af8 \"custom_types.Degrees@75634af8\"]"
21+
22+
;; And so does ddiff
23+
(ddiff/pretty-print (ddiff/diff [(->Degrees 20 \C)]
24+
[(->Degrees 80 \F)]))
25+
;; =>
26+
;; [-#object[custom_types.Degrees 0x660a955 "custom_types.Degrees@660a955"]
27+
;; +#object[custom_types.Degrees 0x40241557 "custom_types.Degrees@40241557"]]
28+
29+
30+
;; Now we set up a custom handler
31+
32+
(defmethod print-method Degrees [degrees out]
33+
(.write out (str (.-amount degrees) "°" (.-unit degrees))))
34+
35+
36+
(pr-str (->Degrees 10 "C"))
37+
;; => "10°C"
38+
39+
(ddiff/pretty-print (ddiff/diff [(->Degrees 20 \C)]
40+
[(->Degrees 20 \C)
41+
(->Degrees 80 \F)]))
42+
;; => [-20°C +80°F]
43+
44+
;; Add Puget handler, to tap into Puget's rich rendering. Will take precedence
45+
;; over `print-method`.
46+
47+
(lambdaisland.deep-diff2.printer-impl/register-print-handler!
48+
`Degrees
49+
(fn [printer value]
50+
[:span
51+
(lambdaisland.deep-diff2.puget.color/document printer :number (str (.-amount value)))
52+
(lambdaisland.deep-diff2.puget.color/document printer :tag "°")
53+
(lambdaisland.deep-diff2.puget.color/document printer :keyword (str (.-unit value)))]))
54+
55+
(ddiff/pretty-print (->Degrees 20 \C))
56+
;; => 20°C (printed with specific colors)
57+
58+
(ddiff/pretty-print (->Degrees 20 \C) (ddiff/printer {:color-markup :html-inline}))
59+
;;=> <span style="color:cyan">20</span><span style="color:magenta">°</span><span style="font-weight:bold;color:yellow">C</span>

0 commit comments

Comments
 (0)