changeset 729:ec8dd7b8bf0c

Updated graph type.
author Jari-Matti M?kel? <jmjm@iki.fi>
date Sun, 03 Feb 2008 19:43:53 +0200
parents 41cad5ca4863
children 5cb236c6fe52
files trunk/src/docgen/docgen.d trunk/src/docgen/document/generator.d trunk/src/docgen/document/htmlgenerator.d trunk/src/docgen/document/latexgenerator.d trunk/src/docgen/document/plaintextgenerator.d trunk/src/docgen/graphutils/dotwriter.d trunk/src/docgen/graphutils/modulenamewriter.d trunk/src/docgen/graphutils/modulepathwriter.d trunk/src/docgen/graphutils/primitives.d trunk/src/docgen/graphutils/writer.d trunk/src/docgen/misc/misc.d trunk/src/docgen/tests/graphs.d
diffstat 12 files changed, 241 insertions(+), 177 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/docgen/docgen.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/docgen.d	Sun Feb 03 19:43:53 2008 +0200
@@ -36,15 +36,19 @@
   options.parser.importPaths = args[2..$-1];
   options.outputDir = args[$-1];
 
+  alias DepGraph.Vertex Vertex;
+  alias DepGraph.Edge Edge;
+
   Module[] cachedModules;
-  Edge[] cachedEdges;
-  Vertex[char[]] cachedVertices;
+  DepGraph cachedGraph;
 
-  void parser(ref Module[] modules, ref Edge[] edges, ref Vertex[char[]] vertices) {
-    if (cachedModules != null) {
+  void parser(ref Module[] modules, ref DepGraph depGraph) {
+    Edge[] edges;
+    Vertex[char[]] vertices;
+
+    if (cachedGraph != null) {
       modules = cachedModules;
-      edges = cachedEdges;
-      vertices = cachedVertices;
+      depGraph = cachedGraph;
       return;
     }
 
@@ -61,13 +65,10 @@
           if (fqn in vertices) {
             debug Stdout.format("{} already set.\n", fqn);
             return;
-
           }
           auto vertex = new Vertex(fqn, path, id++);
-          vertex.type = VertexType.UnlocatableModule;
           vertices[fqn] = vertex;
           debug Stdout.format("Setting {} = {}.\n", fqn, path);
-
         } else {
           vertices[m.moduleFQN] = new Vertex(m.moduleFQN, m.filePath, id++);
           debug Stdout.format("Setting {} = {}.\n", m.moduleFQN, m.filePath);
@@ -76,8 +77,7 @@
       (Module imported, Module importer, bool isPublic) {
         debug Stdout.format("Connecting {} - {}.\n", imported.moduleFQN, importer.moduleFQN);
         auto edge = vertices[imported.moduleFQN].addChild(vertices[importer.moduleFQN]);
-        edge.type = isPublic ? EdgeType.PublicDependency : EdgeType.Dependency;
-        edge.type = id % 2 ? EdgeType.PublicDependency : EdgeType.Dependency; // FIXME: temporary feature for demonstrating public imports
+        edge.isPublic = isPublic;
         edges ~= edge;
       },
       modules
@@ -87,9 +87,11 @@
       (Module a, Module b){ return icompare(a.moduleFQN, b.moduleFQN); }
     );
 
-    cachedVertices = vertices;
+    depGraph.edges = edges;
+    depGraph.vertices = vertices.values;
+
+    cachedGraph = depGraph;
     cachedModules = modules;
-    cachedEdges = edges;
   }
   
   GraphCache graphcache = new DefaultGraphCache();
--- a/trunk/src/docgen/document/generator.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/document/generator.d	Sun Feb 03 19:43:53 2008 +0200
@@ -18,7 +18,7 @@
 debug import tango.io.Stdout;
 
 
-alias void delegate(ref Module[], ref Edge[], ref Vertex[char[]]) ParserDg;
+alias void delegate(ref Module[], ref DepGraph) ParserDg;
 
 abstract class DefaultDocGenerator : DocGenerator {
   protected:
@@ -37,8 +37,7 @@
   ModuleDocWriterFactory moduleDocFactory;
   
   Module[] modules;
-  Edge[] edges;
-  Vertex[char[]] vertices;
+  DepGraph depGraph;
 
   public:
 
@@ -100,7 +99,8 @@
   }
 
   void parseSources() {
-    m_parser(modules, edges, vertices);
+    depGraph = new DepGraph();
+    m_parser(modules, depGraph);
   }
 
   //---
--- a/trunk/src/docgen/document/htmlgenerator.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/document/htmlgenerator.d	Sun Feb 03 19:43:53 2008 +0200
@@ -57,7 +57,9 @@
    * Generates document skeleton.
    */
   void generateDoc() {
-    writeSimpleFile(docFileNames[0], { docWriter.generateFirstPage(); });
+    writeSimpleFile(docFileNames[0], {
+      docWriter.generateFirstPage();
+    });
     /*
     writeSimpleFile(docFileNames[1], {
       docWriter.generateTOC(modules);
@@ -69,7 +71,9 @@
    * Generates a global style sheet.
    */
   void generateStyleSheet() {
-    writeSimpleFile(styleSheetFile, { docWriter.generateCustomPage("stylesheet"); } );
+    writeSimpleFile(styleSheetFile, {
+      docWriter.generateCustomPage("stylesheet");
+    });
   }
 
   /**
@@ -142,7 +146,7 @@
       auto imgFile = outputFile(depGraphFile);
 
       auto writer = graphFactory.createGraphWriter( docWriter, GraphFormat.Dot );
-      writer.generateDepGraph(vertices.values, edges, imgFile);
+      writer.generateDepGraph(depGraph, imgFile);
 
       imgFile.close();
 
--- a/trunk/src/docgen/document/latexgenerator.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/document/latexgenerator.d	Sun Feb 03 19:43:53 2008 +0200
@@ -113,7 +113,7 @@
       auto imgFile = outputFile(depGraphFile);
 
       auto writer = graphFactory.createGraphWriter( docWriter, GraphFormat.Dot );
-      writer.generateDepGraph(vertices.values, edges, imgFile);
+      writer.generateDepGraph(depGraph, imgFile);
 
       imgFile.close();
     });
--- a/trunk/src/docgen/document/plaintextgenerator.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/document/plaintextgenerator.d	Sun Feb 03 19:43:53 2008 +0200
@@ -55,7 +55,9 @@
    * Generates document skeleton.
    */
   void generateDoc() {
-    writeSimpleFile(docFileNames[0], { docWriter.generateFirstPage(); });
+    writeSimpleFile(docFileNames[0], {
+      docWriter.generateFirstPage();
+    });
     
     writeSimpleFile(docFileNames[1], {
       docWriter.generateTOC(modules);
@@ -111,7 +113,7 @@
       auto imgFile = outputFile(depGraphFile);
 
       auto writer = graphFactory.createGraphWriter( docWriter, GraphFormat.Dot );
-      writer.generateDepGraph(vertices.values, edges, imgFile);
+      writer.generateDepGraph(depGraph, imgFile);
 
       imgFile.close();
     });
--- a/trunk/src/docgen/graphutils/dotwriter.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/graphutils/dotwriter.d	Sun Feb 03 19:43:53 2008 +0200
@@ -22,21 +22,24 @@
     super(factory, writer);
   }
 
-  void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
+  void generateDepGraph(DepGraph depGraph, OutputStream imageFile) {
     generateImageTag(imageFile);
     
-    auto image = generateDepImageFile(vertices, edges);
+    auto image = generateDepImageFile(depGraph);
     auto printer = new Print!(char)(new Layout!(char), imageFile);
     printer(image);
   }
 
   protected:
 
-  char[] generateDepImageFile(Vertex[] vertices, Edge[] edges) {
+  char[] generateDepImageFile(DepGraph depGraph) {
     char[] image;
     auto sprint = new Sprint!(char);
+    
+    auto edges = depGraph.edges;
+    auto vertices = depGraph.vertices;
 
-    Vertex[][char[]] verticesByPckgName;
+    DepGraph.Vertex[][char[]] verticesByPckgName;
     if (factory.options.graph.groupByFullPackageName ||
         factory.options.graph.groupByPackageNames) {
       foreach (mod; vertices) {
@@ -51,7 +54,7 @@
 
     if (factory.options.graph.highlightCyclicVertices ||
         factory.options.graph.highlightCyclicEdges)
-      findCycles(vertices, edges);
+      depGraph.markCycles();
 
     image ~= "Digraph ModuleDependencies {\n";
 
@@ -65,9 +68,9 @@
         `  n{} [label="{}",style=filled,fillcolor={}];`\n,
         module_.id,
         nodeName,
-        module_.isCyclic && factory.options.graph.highlightCyclicVertices ?
+        module_.cyclic && factory.options.graph.highlightCyclicVertices ?
           factory.options.graph.cyclicNodeColor :
-        module_.type == VertexType.UnlocatableModule ?
+        module_.incoming.length == 0 && module_.outgoing.length == 0 ?
           factory.options.graph.unlocatableNodeColor :
           factory.options.graph.nodeColor
       );
@@ -78,9 +81,9 @@
         `  n{} -> n{}[color={}];`\n,
         edge.outgoing.id,
         edge.incoming.id,
-        edge.isCyclic ?
+        edge.cyclic ?
           factory.options.graph.cyclicDepColor :
-        edge.type == EdgeType.PublicDependency ?
+        edge.isPublic ?
           factory.options.graph.publicDepColor ~ ",style=bold" :
           factory.options.graph.depColor
       );
@@ -148,18 +151,18 @@
     this.factory = factory;
   }
 
-  override void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
+  override void generateDepGraph(DepGraph depGraph, OutputStream imageFile) {
     generateImageTag(imageFile);
 
-    auto cached = factory.graphCache.getCachedGraph(vertices, edges, GraphFormat.Dot);
+    auto cached = factory.graphCache.getCachedGraph(depGraph, GraphFormat.Dot);
 
     auto printer = new Print!(char)(new Layout!(char), imageFile);
     
     if (cached) {
       printer(cached);
     } else {
-      auto image = generateDepImageFile(vertices, edges);
-      factory.graphCache.setCachedGraph(vertices, edges, GraphFormat.Dot, image);
+      auto image = generateDepImageFile(depGraph);
+      factory.graphCache.setCachedGraph(depGraph, GraphFormat.Dot, image);
       printer(image);
     }
   }
--- a/trunk/src/docgen/graphutils/modulenamewriter.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/graphutils/modulenamewriter.d	Sun Feb 03 19:43:53 2008 +0200
@@ -15,10 +15,13 @@
     super(factory, writer);
   }
 
-  void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
+  void generateDepGraph(DepGraph depGraph, OutputStream imageFile) {
     char[][] contents;
 
-    void doList(Vertex[] v, uint level) {
+    auto edges = depGraph.edges;
+    auto vertices = depGraph.vertices;
+
+    void doList(DepGraph.Vertex[] v, uint level) {
       if (!level) return;
 
       contents ~= "(";
--- a/trunk/src/docgen/graphutils/modulepathwriter.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/graphutils/modulepathwriter.d	Sun Feb 03 19:43:53 2008 +0200
@@ -15,10 +15,13 @@
     super(factory, writer);
   }
 
-  void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
+  void generateDepGraph(DepGraph depGraph, OutputStream imageFile) {
     char[][] contents;
 
-    void doList(Vertex[] v, uint level) {
+    auto edges = depGraph.edges;
+    auto vertices = depGraph.vertices;
+
+    void doList(DepGraph.Vertex[] v, uint level) {
       if (!level) return;
 
       contents ~= "(";
--- a/trunk/src/docgen/graphutils/primitives.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/graphutils/primitives.d	Sun Feb 03 19:43:53 2008 +0200
@@ -4,99 +4,139 @@
  */
 module docgen.graphutils.primitives;
 
-enum EdgeType {
-  Unspecified,
-  Aggregation,
-  Association,
-  Composition,
-  Dependency,
-  Generalization,
-  Inheritance,
-  PublicDependency
-}
+/**
+ * Extendible graph class. Should support separation of concerns now better with mixins.
+ * Provides a method for cycle marking.
+ */
+class Graph(alias V, alias E, int capacity = 1) {
+  static class Edge {
+    Vertex outgoing, incoming;
+    //bool cyclic = true;
 
-enum CycleType {
-  Unspecified,
-  Cyclefree,
-  Cyclic,
-  Reserved
-}
+    this(Vertex o, Vertex i) {
+      outgoing = o;
+      incoming = i;
+      o.outgoingEdges ~= this;
+      i.incomingEdges ~= this;
+    }
 
-class Edge {
-  Vertex outgoing;
-  Vertex incoming;
-  EdgeType type;
-  CycleType cycleType; // used by the cycle algorithm
+    bool cyclic() {
+      return outgoing.cyclic && incoming.cyclic;
+    }
 
-  this(Vertex o, Vertex i, EdgeType type = EdgeType.Unspecified) {
-    this.outgoing = o;
-    this.incoming = i;
-    this.type = type;
+    mixin E;
   }
 
-  bool isCyclic() {
-    return cycleType == CycleType.Cyclic;
+  static class Vertex {
+    Edge[] incomingEdges;
+    Edge[] outgoingEdges;
+    bool cyclic = true;
+
+    Edge addChild(Vertex v) {
+      return new Edge(v, this);
+    }
+
+    Edge addParent(Vertex v) {
+      return v.addChild(this);
+    }
+
+    Vertex[] incoming() {
+      Vertex[] tmp;
+
+      foreach(edge; incomingEdges)
+        tmp ~= edge.outgoing;
+
+      return tmp;
+    }
+
+    Vertex[] outgoing() {
+      Vertex[] tmp;
+
+      foreach(edge; outgoingEdges)
+        tmp ~= edge.incoming;
+
+      return tmp;
+    }
+
+    mixin V;
+  }
+
+  Vertex[] vertices;
+  Edge[] edges;
+
+  this() {
+    vertices.length = capacity;
+    vertices.length = 0;
+    edges.length = capacity;
+    edges.length = 0;
+  }
+
+  void add(Vertex vertex) { vertices ~= vertex; }
+
+  void add(Edge edge) { edges ~= edge; }
+
+  void connect(Vertex from, Vertex to) { edges ~= from.addParent(to); }
+
+  void connect(int from, int to) { connect(vertices[from], vertices[to]); }
+
+  /**
+   * Starts from non-cyclic nodes and propagates two both directions.
+   * Bugs: marks non-cyclic imports between two cycles as cyclic. Could be fixed later if it's really needed (slow)
+   */
+  void markCycles() {
+    void mark(Vertex v) {
+      v.cyclic = false;
+      foreach(o; v.outgoing) {
+        if (!o.cyclic) continue;
+
+        // propagate
+        bool cyclic = false;
+        foreach(p; o.incoming) if (p.cyclic) { cyclic = true; break; }
+        if (!cyclic) mark(o);
+      }
+    }
+
+    void mark2(Vertex v) {
+      v.cyclic = false;
+      foreach(o; v.incoming) {
+        if (!o.cyclic) continue;
+
+        // propagate
+        bool cyclic = false;
+        foreach(p; o.outgoing) if (p.cyclic) { cyclic = true; break; }
+        if (!cyclic) mark2(o);
+      }
+    }
+
+    foreach(e; vertices)
+      if (e.cyclic) {
+        if (!e.incoming.length) mark(e);
+        if (!e.outgoing.length) mark2(e);
+      }
   }
 }
 
-enum VertexType {
-  Module,
-  UnlocatableModule,
-  Package,
-  Class,
-  Interface,
-  Trait
+template Empty() {}
+
+
+// graph elements used in dep graphs
+
+
+template DepEdge() {
+  bool isPublic; /// Public import.
+  bool isStatic; /// Static import.
 }
 
-class Vertex {
+template DepVertex() {
   char[] name;
   char[] location;
   uint id;
 
-  Edge[] incomingEdges;
-  Edge[] outgoingEdges;
-  VertexType type;
-
   this(char[] name, char[] location, uint id = 0) {
     this.name = name;
     this.location = location;
     this.id = id;
   }
-
-  Edge addChild(Vertex v, EdgeType type = EdgeType.Unspecified) {
-    auto edge = new Edge(v, this, type);
-    incomingEdges ~= edge;
-    v.outgoingEdges ~= edge;
-    return edge;
-  }
-
-  Edge addParent(Vertex v, EdgeType type = EdgeType.Unspecified) {
-    return v.addChild(this, type);
-  }
-
-  Vertex[] incoming() {
-    Vertex[] tmp;
-
-    foreach(edge; incomingEdges)
-      tmp ~= edge.outgoing;
+}
 
-    return tmp;
-  }
-
-  Vertex[] outgoing() {
-    Vertex[] tmp;
-
-    foreach(edge; outgoingEdges)
-      tmp ~= edge.incoming;
-
-    return tmp;
-  }
-
-  bool isCyclic() {
-    foreach(edge; outgoingEdges)
-      if (edge.isCyclic)
-        return true;
-
-    return false;
-  }
-}
+alias Graph!(DepVertex, DepEdge, 100) DepGraph;
--- a/trunk/src/docgen/graphutils/writer.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/graphutils/writer.d	Sun Feb 03 19:43:53 2008 +0200
@@ -10,7 +10,7 @@
 debug import tango.io.Stdout;
 
 interface GraphWriter {
-  void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile);
+  void generateDepGraph(DepGraph depGraph, OutputStream imageFile);
 }
 
 interface GraphWriterFactory : WriterFactory {
@@ -20,7 +20,7 @@
 interface CachingGraphWriterFactory : GraphWriterFactory {
   GraphCache graphCache();
 }
-
+/+
 /**
  * Marks all cycles in the graph.
  *
@@ -67,6 +67,7 @@
         debug Stderr("*\n");
       }
 }
++/
 
 abstract class AbstractGraphWriter : AbstractWriter!(GraphWriterFactory), GraphWriter {
   protected:
@@ -84,31 +85,29 @@
 class DefaultGraphCache : GraphCache {
   private:
     
-  char[][Object[]][Object[]][GraphFormat] m_graphCache;
+  char[][Object][GraphFormat] m_graphCache;
 
   public:
 
-  char[] getCachedGraph(Object[] vertices, Object[] edges, GraphFormat format) {
+  char[] getCachedGraph(Object graph, GraphFormat format) {
     debug Stdout("Starting graph lookup\n");
-    debug Stdout(&vertices, &edges, format).newline;
+    debug Stdout(&graph, format).newline;
     debug Stdout(&m_graphCache).newline;
     
     auto lookup1 = format in m_graphCache;
     if (lookup1) {
-      auto lookup2 = edges in *lookup1;
+      auto lookup2 = graph in *lookup1;
       if (lookup2) {
-        auto lookup3 = vertices in *lookup2;
-        if (lookup3)
-          return *lookup3;
+          return *lookup2;
       }
     }
     debug Stdout("Graph cache miss!\n");
     return null;
   }
 
-  void setCachedGraph(Object[] vertices, Object[] edges, GraphFormat format, char[]
+  void setCachedGraph(Object graph, GraphFormat format, char[]
       contents) {
-    m_graphCache[format][edges][vertices] = contents;
+    m_graphCache[format][graph] = contents;
     debug Stdout("Graph cache updated!\n");
   }
 }
--- a/trunk/src/docgen/misc/misc.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/misc/misc.d	Sun Feb 03 19:43:53 2008 +0200
@@ -14,8 +14,8 @@
 }
 
 interface GraphCache {  
-  char[] getCachedGraph(Object[] vertices, Object[] edges, GraphFormat format);
-  void setCachedGraph(Object[] vertices, Object[] edges, GraphFormat format, char[] contents);
+  char[] getCachedGraph(Object graph, GraphFormat format);
+  void setCachedGraph(Object graph, GraphFormat format, char[] contents);
 }
 
 interface CachingDocGenerator : DocGenerator {
--- a/trunk/src/docgen/tests/graphs.d	Sat Feb 02 23:17:14 2008 +0100
+++ b/trunk/src/docgen/tests/graphs.d	Sun Feb 03 19:43:53 2008 +0200
@@ -11,7 +11,10 @@
 import tango.io.FileConduit;
 import dil.semantic.Module;
 
-void saveDefaultGraph(Vertex[] vertices, Edge[] edges, char[] fname) {
+alias DepGraph.Edge Edge;
+alias DepGraph.Vertex Vertex;
+
+void saveDefaultGraph(DepGraph depGraph, char[] fname) {
   auto gen = new TestDocGenerator;
   gen.options.graph.highlightCyclicVertices = true;
   gen.options.graph.imageFormat = ImageFormat.SVG;
@@ -28,7 +31,7 @@
     GraphFormat.Dot
   );
   
-  writer.generateDepGraph(vertices, edges, file);
+  writer.generateDepGraph(depGraph, file);
   
   file.close();
   file2.close();
@@ -37,71 +40,72 @@
 // no edges
 //@unittest
 void graph1() {
-  auto a = new Vertex("mod_a", "path.to.mod_a", 1);
-  auto b = new Vertex("mod_b", "path.to.mod_b", 2);
-  auto c = new Vertex("mod_c", "path.to.mod_c", 3);
+  auto g = new DepGraph;
+  g.add(new Vertex("mod_a", "path.to.mod_a", 1));
+  g.add(new Vertex("mod_b", "path.to.mod_b", 2));
+  g.add(new Vertex("mod_c", "path.to.mod_c", 3));
   
-  saveDefaultGraph( [a,b,c], null, "graph1.dot" );
+  saveDefaultGraph(g, "graph1.dot");
 }
 
 
 // simple tree structure
 //@unittest
 void graph2() {
-  auto a = new Vertex("mod_a", "path.to.mod_a", 1);
-  auto b = new Vertex("mod_b", "path.to.mod_b", 2);
-  auto c = new Vertex("mod_c", "path.to.mod_c", 3);
-  auto d = new Vertex("mod_d", "path.to.mod_d", 4);
+  auto g = new DepGraph;
+  g.add(new Vertex("mod_a", "path.to.mod_a", 1));
+  g.add(new Vertex("mod_b", "path.to.mod_b", 2));
+  g.add(new Vertex("mod_c", "path.to.mod_c", 3));
+  g.add(new Vertex("mod_d", "path.to.mod_d", 4));
 
-  Edge[] edges;
-  edges ~= a.addChild(b);
-  edges ~= a.addChild(c);
-  edges ~= c.addChild(d);
+  g.connect(1, 0);
+  g.connect(2, 0);
+  g.connect(3, 2);
   
-  saveDefaultGraph( [a,b,c,d], edges, "graph2.dot" );
+  saveDefaultGraph(g, "graph2.dot");
 }
 
 // circular imports
 //@unittest
 void graph3() {
-  auto a = new Vertex("mod_a", "path.to.mod_a", 1);
-  auto b = new Vertex("mod_b", "path.to.mod_b", 2);
-  auto c = new Vertex("mod_c", "path.to.mod_c", 3);
-  auto d = new Vertex("mod_d", "path.to.mod_d", 4);
+  auto g = new DepGraph;
+  g.add(new Vertex("mod_a", "path.to.mod_a", 1));
+  g.add(new Vertex("mod_b", "path.to.mod_b", 2));
+  g.add(new Vertex("mod_c", "path.to.mod_c", 3));
+  g.add(new Vertex("mod_d", "path.to.mod_d", 4));
 
-  Edge[] edges;
-  edges ~= a.addChild(b);
-  edges ~= b.addChild(c);
-  edges ~= c.addChild(a);
-
-  saveDefaultGraph( [a,b,c,d], edges, "graph3.dot" );
+  g.connect(1, 0);
+  g.connect(2, 1);
+  g.connect(0, 2);
+  
+  saveDefaultGraph(g, "graph3.dot");
 }
 
 // more complex graph
 //@unittest
 void graph4() {
-  auto a = new Vertex("mod_a", "path.to.mod_a", 1);
-  auto b = new Vertex("mod_b", "path.to.mod_b", 2);
-  auto c = new Vertex("mod_c", "path.to.mod_c", 3);
-  auto d = new Vertex("mod_d", "path.to.mod_d", 4);
-  auto e = new Vertex("mod_e", "path.to.mod_e", 5);
-  auto f = new Vertex("mod_f", "path.to.mod_f", 6);
-  auto g = new Vertex("mod_g", "path.to.mod_g", 7);
+  auto g = new DepGraph;
+  g.add(new Vertex("mod_a", "path.to.mod_a", 1));
+  g.add(new Vertex("mod_b", "path.to.mod_b", 2));
+  g.add(new Vertex("mod_c", "path.to.mod_c", 3));
+  g.add(new Vertex("mod_d", "path.to.mod_d", 4));
+  g.add(new Vertex("mod_e", "path.to.mod_e", 5));
+  g.add(new Vertex("mod_f", "path.to.mod_f", 6));
+  g.add(new Vertex("mod_g", "path.to.mod_g", 7));
 
-  Edge[] edges;
-  edges ~= a.addChild(b);
-  edges ~= b.addChild(c);
-  edges ~= c.addChild(a);
-  edges ~= d.addChild(a);
-  edges ~= e.addChild(a);
-  edges ~= b.addChild(d);
-  edges ~= b.addChild(e);
-  edges ~= g.addChild(a);
-  edges ~= b.addChild(f);
-  edges ~= g.addChild(f);
-  edges ~= a.addChild(g);
+  g.connect(1, 0);
+  g.connect(2, 1);
+  g.connect(0, 2); 
+  g.connect(0, 3);
+  g.connect(0, 4);
+  g.connect(3, 1);
+  g.connect(4, 1);
+  g.connect(0, 6);
+  g.connect(5, 1);
+  g.connect(5, 6);
+  g.connect(6, 0);
 
-  saveDefaultGraph( [a,b,c,d,e,f,g], edges, "graph4.dot" );
+  saveDefaultGraph(g, "graph4.dot");
 }
 
 
@@ -129,11 +133,11 @@
     [ "c" ], [ "docgen/teststuff/" ],
     null, true, -1,
     (char[] fqn, char[] path, Module m) {
-      vertices[m.moduleFQN] = new Vertex(m.moduleFQN, m.filePath, id++);
+      vertices[m.moduleFQN] = new DepGraph.Vertex(m.moduleFQN, m.filePath, id++);
     },
     (Module imported, Module importer, bool isPublic) {
       auto edge = vertices[imported.moduleFQN].addChild(vertices[importer.moduleFQN]);
-      edge.type = isPublic ? EdgeType.PublicDependency : EdgeType.Dependency;
+      edge.isPublic = isPublic;
       edges ~= edge;
     },
     modules
@@ -144,7 +148,11 @@
     GraphFormat.Dot
   );
   
-  writer.generateDepGraph(vertices.values, edges, imgFile);
+  auto graph = new DepGraph;
+  graph.edges = edges;
+  graph.vertices = vertices.values;
+
+  writer.generateDepGraph(graph, imgFile);
   
   file.close();
   imgFile.close();