Interactive exploration and modification of Clojure data.
Clojure
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src/mangosteen
.gitignore
LICENSE
README.md
project.clj

README.md

mangosteen

A library for interactive exploration of Clojure data.

Usage

Sometimes you have a gnarly piece of data and want to explore it. This can be done at the REPL, but navigation and exploration of the tree end up looking like this.

user> my-data
(let [x (rand-int 6) y (rand-int 10)] (if (< x y) x (+ y x)))
user> (nth *1 1)
[x (rand-int 6) y (rand-int 10)]
user> (class *1)
clojure.lang.PersistentVector
user> (nth *2 2)
y
user> (class *1)
clojure.lang.Symbol

That's far from ideal. In many cases, you want a more idiomatic way of walking a data structure-- without leaving the REPL. That's what Mangosteen, an interactive wrapper around clojure.zip, is for.

Exploration

Use the function explore to navigate your data structure, like so.

user=> (use 'mangosteen.core)
nil
user=> (def my-data '(defn f [x] (if (= (mod x 2) 0) (quot x 2) (+ (* x 3) 1))))
#'user/my-data
user=> (explore my-data)

---------------------------------------------------------------------------
CURRENT FORM:
(defn f [x] (if (= (mod x 2) 0) (quot x 2) (+ (* x 3) 1)))
... of class clojure.lang.PersistentList

0: defn
1: f
2: [x]
3: (if (= (mod x 2) 0) (quot x 2) (+ (* x 3) 1))

(s)elect, (q)uit, (u)p to parent, or (0, 1, ...) to descend.
Your choice? 3


---------------------------------------------------------------------------
CURRENT FORM:
(if (= (mod x 2) 0) (quot x 2) (+ (* x 3) 1))
... of class clojure.lang.PersistentList

... parent is: (defn f [x] (if (= (mod x 2) 0) (quot x 2) (+ (* x 3) 1)))

0: if
1: (= (mod x 2) 0)
2: (quot x 2)
3: (+ (* x 3) 1)

(s)elect, (q)uit, (u)p to parent, or (0, 1, ...) to descend.
Your choice? 1


---------------------------------------------------------------------------
CURRENT FORM:
(= (mod x 2) 0)
... of class clojure.lang.PersistentList

... parent is: (if (= (mod x 2) 0) (quot x 2) (+ (* x 3) 1))

0: =
1: (mod x 2)
2: 0

(s)elect, (q)uit, (u)p to parent, or (0, 1, ...) to descend.
Your choice? s

[:select (= (mod x 2) 0)]

If (s)elect is used, the exploration terminates and the subform is returned in [:select <subform>]. If (q)uit is used, then [:quit] is returned.

"Modification"

Often it's desirable to "modify" a nested data structure. (I use quotes because the original is unchanged: a modified copy is returned.)

In modification, the function interact is used. (S)elect is used to choose a node for modification, and (q)uit is used to stop making edits. The modified copy of the data (with all edits) will be returned.


user=> (def my-data [[1 2] [3 nil]])
#'user/my-data
user=> (interact my-data)

---------------------------------------------------------------------------
CURRENT FORM:
[[1 2] [3 nil]]
... of class clojure.lang.PersistentVector

0: [1 2]
1: [3 nil]

(s)elect, (q)uit, (u)p to parent, or (0, 1, ...) to descend.
Your choice? 1


---------------------------------------------------------------------------
CURRENT FORM:
[3 nil]
... of class clojure.lang.PersistentVector

... parent is: [[1 2] [3 nil]]

0: 3
1: nil

(s)elect, (q)uit, (u)p to parent, or (0, 1, ...) to descend.
Your choice? 1


---------------------------------------------------------------------------
CURRENT FORM:
nil
... of class nil

... parent is: [3 nil]

... is atomic

(s)elect, (q)uit, (u)p to parent, or (0, 1, ...) to descend.
Your choice? s

Edit to what? 4


---------------------------------------------------------------------------
CURRENT FORM:
4
... of class java.lang.Long

... parent is: [3 4]

... is atomic

(s)elect, (q)uit, (u)p to parent, or (0, 1, ...) to descend.
Your choice? q

[[1 2] [3 4]]

License

Copyright © 2014 Michael O. Church. Distributed under the MIT License.