nitdoc: introduce GraphsPhase
authorAlexandre Terrasa <alexandre@moz-code.org>
Wed, 4 Feb 2015 20:08:09 +0000 (21:08 +0100)
committerAlexandre Terrasa <alexandre@moz-code.org>
Wed, 4 Feb 2015 20:17:38 +0000 (21:17 +0100)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

src/doc/doc_pages.nit
src/doc/doc_phases/doc_graphs.nit [new file with mode: 0644]
src/doc/doc_phases/doc_phases.nit
src/nitdoc.nit

index 2a0f920..4239532 100644 (file)
@@ -24,8 +24,6 @@ redef class ToolContext
        private var opt_source = new OptionString("link for source (%f for filename, %l for first line, %L for last line)", "--source")
        private var opt_sharedir = new OptionString("directory containing nitdoc assets", "--sharedir")
        private var opt_shareurl = new OptionString("use shareurl instead of copy shared files", "--shareurl")
-       private var opt_nodot = new OptionBool("do not generate graphes with graphviz", "--no-dot")
-
        private var opt_custom_title = new OptionString("custom title for homepage", "--custom-title")
        private var opt_custom_brand = new OptionString("custom link to external site", "--custom-brand")
        private var opt_custom_intro = new OptionString("custom intro text for homepage", "--custom-overview-text")
@@ -45,8 +43,7 @@ redef class ToolContext
                super
 
                var opts = option_context
-               opts.add_option(opt_dir, opt_source, opt_sharedir, opt_shareurl,
-                               opt_nodot)
+               opts.add_option(opt_dir, opt_source, opt_sharedir, opt_shareurl)
                opts.add_option(opt_custom_title, opt_custom_footer, opt_custom_intro, opt_custom_brand)
                opts.add_option(opt_github_upstream, opt_github_base_sha1, opt_github_gitdir)
                opts.add_option(opt_piwik_tracker, opt_piwik_site_id)
@@ -258,36 +255,6 @@ abstract class NitdocPage
        # Build page content template
        fun tpl_content is abstract
 
-       # Clickable graphviz image using dot format
-       # return null if no graph for this page
-       fun tpl_graph(dot: Buffer, name: String, title: nullable String): nullable TplArticle do
-               if ctx.opt_nodot.value then return null
-               var output_dir = ctx.output_dir
-               var path = output_dir / name
-               var path_sh = path.escape_to_sh
-               var file = new OFStream.open("{path}.dot")
-               file.write(dot)
-               file.close
-               sys.system("\{ test -f {path_sh}.png && test -f {path_sh}.s.dot && diff -- {path_sh}.dot {path_sh}.s.dot >/dev/null 2>&1 ; \} || \{ cp -- {path_sh}.dot {path_sh}.s.dot && dot -Tpng -o{path_sh}.png -Tcmapx -o{path_sh}.map {path_sh}.s.dot ; \}")
-               var fmap = new IFStream.open("{path}.map")
-               var map = fmap.read_all
-               fmap.close
-
-               var article = new TplArticle("graph")
-               var alt = ""
-               if title != null then
-                       article.title = title
-                       alt = "alt='{title.html_escape}'"
-               end
-               article.css_classes.add "text-center"
-               var content = new Template
-               var name_html = name.html_escape
-               content.add "<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
-               content.add map
-               article.content = content
-               return article
-       end
-
        # A (source) link template for a given location
        fun tpl_showsource(location: nullable Location): nullable String
        do
@@ -632,15 +599,6 @@ class NitdocModule
                # Display lists
                var section = new TplSection.with_title("dependencies", "Dependencies")
 
-               # Graph
-               var mmodules = new HashSet[MModule]
-               mmodules.add_all mmodule.nested_mmodules
-               mmodules.add_all imports
-               if clients.length < 10 then mmodules.add_all clients
-               mmodules.add mmodule
-               var graph = tpl_dot(mmodules)
-               if graph != null then section.add_child graph
-
                # Imports
                var lst = new Array[MModule]
                if not lst.is_empty then
@@ -665,26 +623,6 @@ class NitdocModule
                article.content = list
                return article
        end
-
-       # Genrate dot hierarchy for class inheritance
-       fun tpl_dot(mmodules: Collection[MModule]): nullable TplArticle do
-               # build graph
-               var op = new RopeBuffer
-               var name = "dep_module_{mmodule.nitdoc_id}"
-               op.append("digraph \"{name.escape_to_dot}\" \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
-               for mmodule in poset do
-                       if mmodule == self.mmodule then
-                               op.append("\"{mmodule.name.escape_to_dot}\"[shape=box,margin=0.03];\n")
-                       else
-                               op.append("\"{mmodule.name.escape_to_dot}\"[URL=\"{mmodule.nitdoc_url.escape_to_dot}\"];\n")
-                       end
-                       for omodule in poset[mmodule].direct_greaters do
-                               op.append("\"{mmodule.name.escape_to_dot}\"->\"{omodule.name.escape_to_dot}\";\n")
-                       end
-               end
-               op.append("\}\n")
-               return tpl_graph(op, name, null)
-       end
 end
 
 # A class page
@@ -762,16 +700,6 @@ class NitdocClass
                # Display lists
                var section = new TplSection.with_title("inheritance", "Inheritance")
 
-               # Graph
-               var mclasses = new HashSet[MClass]
-               mclasses.add_all hancestors
-               mclasses.add_all hparents
-               mclasses.add_all hchildren
-               mclasses.add_all hdescendants
-               mclasses.add mclass
-               var graph = tpl_dot(mclasses)
-               if graph != null then section.add_child graph
-
                # parents
                if not hparents.is_empty then
                        var lst = hparents.to_a
@@ -819,39 +747,6 @@ class NitdocClass
                end
                return article
        end
-
-       # Generate dot hierarchy for classes
-       fun tpl_dot(mclasses: Collection[MClass]): nullable TplArticle do
-               var op = new RopeBuffer
-               var name = "dep_class_{mclass.nitdoc_id}"
-               op.append("digraph \"{name.escape_to_dot}\" \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
-               var classes = poset.to_a
-               var todo = new Array[MClass]
-               var done = new HashSet[MClass]
-               mainmodule.linearize_mclasses(classes)
-               if not classes.is_empty then todo.add classes.first
-               while not todo.is_empty do
-                       var c = todo.shift
-                       if done.has(c) then continue
-                       done.add c
-                       if c == mclass then
-                               op.append("\"{c.name.escape_to_dot}\"[shape=box,margin=0.03];\n")
-                       else
-                               op.append("\"{c.name.escape_to_dot}\"[URL=\"{c.nitdoc_url.escape_to_dot}\"];\n")
-                       end
-                       var smallers = poset[c].direct_smallers
-                       if smallers.length < 10 then
-                               for c2 in smallers do
-                                       op.append("\"{c2.name.escape_to_dot}\"->\"{c.name.escape_to_dot}\";\n")
-                               end
-                               todo.add_all smallers
-                       else
-                               op.append("\"...\"->\"{c.name.escape_to_dot}\";\n")
-                       end
-               end
-               op.append("\}\n")
-               return tpl_graph(op, name, null)
-       end
 end
 
 # A MProperty page
diff --git a/src/doc/doc_phases/doc_graphs.nit b/src/doc/doc_phases/doc_graphs.nit
new file mode 100644 (file)
index 0000000..6013088
--- /dev/null
@@ -0,0 +1,123 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Adds importation and class hierarchy graphs.
+module doc_graphs
+
+import doc_poset
+
+redef class ToolContext
+
+       # Do not generate `graphviz` diagrams.
+       var opt_nodot = new OptionBool("do not generate graphes with graphviz", "--no-dot")
+
+       redef init do
+               super
+               option_context.add_option(opt_nodot)
+       end
+end
+
+# This phase insert importation and inheritance graphs into pages.
+class GraphPhase
+       super DocPhase
+
+       redef fun apply do
+               if ctx.opt_nodot.value then return
+               for page in doc.pages do
+                       var article = page.build_graph(self, doc)
+                       if article == null then continue
+                       # FIXME avoid diff
+                       # page.root.add article
+                       page.root.children[1].children.insert(article, 0)
+               end
+       end
+end
+
+redef class DocPage
+       # Build dot graph articles from `mmodules` list.
+       #
+       # Since only `MEntity pages` contain a graph, this method returns null in all
+       # other cases.
+       private fun build_graph(v: GraphPhase, doc: DocModel): nullable GraphArticle do return null
+end
+
+# TODO graph generation can be factorized in POSet.
+
+redef class MModulePage
+       redef fun build_graph(v, doc) do
+               var op = new FlatBuffer
+               var name = "dep_module_{mentity.nitdoc_id}"
+               op.append("digraph \"{name.escape_to_dot}\" \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
+               for mmodule in poset do
+                       if mmodule == self.mentity then
+                               op.append("\"{mmodule.name.escape_to_dot}\"[shape=box,margin=0.03];\n")
+                       else
+                               op.append("\"{mmodule.name.escape_to_dot}\"[URL=\"{mmodule.nitdoc_url.escape_to_dot}\"];\n")
+                       end
+                       for omodule in poset[mmodule].direct_greaters do
+                               op.append("\"{mmodule.name.escape_to_dot}\"->\"{omodule.name.escape_to_dot}\";\n")
+                       end
+               end
+               op.append("\}\n")
+               return new GraphArticle(name, op)
+       end
+end
+
+redef class MClassPage
+       redef fun build_graph(v, doc) do
+               var op = new FlatBuffer
+               var name = "dep_class_{mentity.nitdoc_id}"
+               op.append("digraph \"{name.escape_to_dot}\" \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
+               var classes = poset.to_a
+               var todo = new Array[MClass]
+               var done = new HashSet[MClass]
+               doc.mainmodule.linearize_mclasses(classes)
+               if not classes.is_empty then todo.add classes.first
+               while not todo.is_empty do
+                       var c = todo.shift
+                       if done.has(c) then continue
+                       done.add c
+                       if c == self.mentity then
+                               op.append("\"{c.name.escape_to_dot}\"[shape=box,margin=0.03];\n")
+                       else
+                               op.append("\"{c.name.escape_to_dot}\"[URL=\"{c.nitdoc_url.escape_to_dot}\"];\n")
+                       end
+                       var smallers = poset[c].direct_smallers
+                       if smallers.length < 10 then
+                               for c2 in smallers do
+                                       op.append("\"{c2.name.escape_to_dot}\"->\"{c.name.escape_to_dot}\";\n")
+                               end
+                               todo.add_all smallers
+                       else
+                               op.append("\"...\"->\"{c.name.escape_to_dot}\";\n")
+                       end
+               end
+               op.append("\}\n")
+               return new GraphArticle(name, op)
+       end
+end
+
+# An article that display an importation or inheritance graph.
+#
+# The graph is stored in dot format.
+# The final output is delayed untill rendering.
+class GraphArticle
+       super DocComposite
+
+       # Graph ID (used for outputing file with names).
+       var id: String
+
+       # Dot script of the graph.
+       var dot: Text
+end
index e9f5965..5719856 100644 (file)
@@ -19,3 +19,4 @@ module doc_phases
 
 import doc_structure
 import doc_poset
+import doc_graphs
index e1bd571..8d37650 100644 (file)
@@ -37,7 +37,8 @@ private class Nitdoc
                        new MakePagePhase(toolcontext, doc),
                        new POSetPhase(toolcontext, doc),
                        new ConcernsPhase(toolcontext, doc),
-                       new StructurePhase(toolcontext, doc): DocPhase]
+                       new StructurePhase(toolcontext, doc),
+                       new GraphPhase(toolcontext, doc): DocPhase]
 
                for phase in phases do
                        toolcontext.info("# {phase.class_name}", 1)