Commits

Karsten Schmidt committed 685baae

adding graph operations to select emitter and leave nodes, overloading defgraph macro to automatically deserialize graph from JSON

Comments (0)

Files changed (1)

src/estuary/core.clj

   [graph uuid]
   `(get (:nodes (deref ~graph)) ~uuid))
 
+(defn all-node-ids
+  "Returns a set of all node IDs in the graph."
+  [graph]
+  (reduce #(conj %1 %2) #{} (keys (:nodes @graph))))
+
+(defn target-node-ids
+  "Returns a set of all node IDs which are targets of other nodes in the graph."
+  [graph]
+  (reduce
+    (fn[targets n]
+      (let [ids (map #(:id %) (:targets @(val n)))]
+        (if-not (nil? (seq ids))
+          (reduce #(conj %1 %2) targets ids)
+          targets)))
+    #{} (:nodes @graph)))
+
+(defn nodes-with-targets
+  "Returns a set of all node IDs which have defined targets in the graph."
+  [graph]
+  (map #(key %)
+       (filter
+         #(> (count (:targets @(val %))) 0)
+         (:nodes @graph))))
+
+(defn emitters
+  "Returns a set of all node IDs which have defined targets, but are
+not targets themselves in the graph, the opposite of the set returned
+by (leaves)."
+  [graph]
+  (let [all (all-node-ids graph)
+        targets (target-node-ids graph)]
+    (reduce #(disj %1 %2) all targets)))
+
+(defn leaves
+  "Returns a set of all node IDs which have no targets, but are
+targets themselves in the graph, the opposite of the set returned
+by (emitters)."
+  [graph]
+  (let [all (all-node-ids graph)
+        with-targets (nodes-with-targets graph)]
+    (reduce #(disj %1 %2) all with-targets)))
+
 (defn conn!
   "Creates a connection from the given source node to a target node. The nodes need to be either supplied
 as variables or UUIDs. The port parameter is the key of the target's input terminal."
       (send src assoc :targets targets) (await src))))
 
 (defmacro defgraph
-  "Creates a new atom based map container for nodes and assigns it to the given variable."
-  [id]
+  "Creates a new atom based map container for nodes and assigns it to the given variable.
+If also supplied with JSON string, the graph is initialized using (deserialize-graph)."
+  ([id]
   `(def ~id (atom {:nodes {}})))
+  ([id json]
+    `(do (defgraph ~id) (deserialize-graph ~id ~json))))
 
 (defmacro defnode
   "Creates a new agent based node with the given initial state and update handler function.
    Graph should be empty and needs to have been created with defgraph previously."
   [graph json]
   (doseq [node (json/parse-string json true)]
-    (let [a (agent node)] (swap! graph (fn[g n] (assoc g :nodes (assoc (:nodes g) (:id @n) n))) a)))
+    (let [a (agent node)]
+      (swap! graph
+        (fn[g n] (assoc g :nodes (assoc (:nodes g) (:id @n) n))) a)))
   (prepare-targets graph))
 
 (defn start-ticker
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.