Fork me on GitHub
Jakub Holý (HolyJak)10:11:06

Hi! I am trying to display a TinkerGraph composed of TinkerEdges and TinkerVertices. I have extended clojure.core.protocols/Datafiable and I can manually (datafy a-graph) but Portal still displays it just as an #object[..] I can datafy the graph before I tap it but the edges and vertices underneath it will still show just as objects. What am I doing wrong? 🙏 I see I can manually datafy a thing via a command / shift-enter but that does not seem to be working (while in the REPL I see it does so it is not a problem with my protocol extension)


Portal doesn't automatically datafy values, but you can do so with something like Also, as far as I'm aware datafy isn't recursive so you would need to walk the value and datafy each node yourself.


Yeah, it's a bit of a gotcha that by the time you get to the #object[..] representation, you can't easily get the datafied version, as I recall. The workflow bites me from time to time. I think Portal is correct to not automatically datafy but it feels like it loses the metadata in some contexts and you can datafy thing in "Portal-land" at that point?

Jakub Holý (HolyJak)18:11:08

Yes it looks like that since I can datafy it from the REPL but calling datafy on the value via the portal command does nothing. Though here it is not Metadata but satisfies?


Also, regarding recursion, that's entirely up to whatever datafy extension you've written: your datafy could be shallow or recursive -- but the concept behind datafy/`nav` is that it should represent lazy navigation between the data representation and the "object" representation, so that's generally going to be a shallow datafication for display and then you nav back to the "object" side to get to another ("native") part of the thing, analogous to the pure data get navigation you did in the display side.

💯 1
Jakub Holý (HolyJak)18:11:23

Actually recursive would blow up here b/c the data is a graph w/ loops so we'd never finish. But I want to know why the datafy command isn't working and I guess I'd want a datafy-all (ie (map datafy...) command if selected is a collection of Datafiable things.


I think it might be related to what's being selected exactly :thinking_face:


With the value #object [...] does your selection include the #object tag or just the vector?


I just tested the datafy command on 0.33.0 and it seems to work for me using:

(require '[clojure.core.protocols :refer [Datafiable]])

(extend-protocol Datafiable
  (datafy [^ this]
    {:name          (.getName this)
     :absolute-path (.getAbsolutePath this)
     :flags         (cond-> #{}
                      (.canRead this)     (conj :read)
                      (.canExecute this)  (conj :execute)
                      (.canWrite this)    (conj :write)
                      (.exists this)      (conj :exists)
                      (.isAbsolute this)  (conj :absolute)
                      (.isFile this)      (conj :file)
                      (.isDirectory this) (conj :directory)
                      (.isHidden this)    (conj :hidden))
     :size          (.length this)
     :last-modified (.lastModified this)
     :uri           (.toURI this)
     :files         (seq (.listFiles this))
     :parent        (.getParentFile this)}))

Jakub Holý (HolyJak)18:11:46

I see, I'll test what was selected when I get to my pc.


When Portal encounters an unknown type, it will pr-str it and send it to the UI. The UI will try and parse it as edn for convenience. It does introduce the issue of nested children which aren't the object that was sent to Portal, only the root tagged literal will get you back to the tapped object.

Jakub Holý (HolyJak)19:11:16

You were right, selecting also the #object part and not just the vector worked. I guess the datafy command is offered on the inner [..] b/c a vector is datafiable? (`(satisfies? clojure.core.protocols/Datafiable []) => true` ) Perhaps it would make sense to exclude clojure collections from stuff that can be datafied by the command, since they already are data and thus it makes no sense? And there will be lesser chance of the confusion I had.

Jakub Holý (HolyJak)19:11:40

Perhaps anything that is coll? (not sure about including maps but…) should not have datafy but should instead have datafy-all (in the tradition of do*all*). WDYT?


No, because they can have metadata that provides datafication.

☝️ 1

next.jdbc uses metadata on regular Clojure collections to provide datafy/`nav`, for example.

Jakub Holý (HolyJak)19:11:12

I see, you mean the user could provide a custom way to datafy a vector and its content? Would it make sense to extend the check to

((every-pred  coll? #(-> % meta 'clojure.core.protocols/datafy)) x)


I think the main issue here is Portal not making it clear what you have selected. When you select the tagged-literal, you are selecting the underlying object. When you select the vector, you are selecting the :form of the tagged-literal.

👍 1

Previously, Portal wouldn't try parsing the pr-str of the object, so it was impossible to select anything aside from the underlying object. I eventually added the parsing as a convenience since most objects print valid edn.


However, now you have multiple things you can select :thinking_face:

Daniel Slutsky21:11:53

On the next #visual-tools meeting, @domagala.lukas & @djblue will present #calva Notebooks and their integration with #portal:

clojure-spin 5
calva 5
🚀 3