uml: Added UML class diagram generation from a Nit model
authorLucas Bajolet <r4pass@hotmail.com>
Wed, 17 Sep 2014 20:12:49 +0000 (16:12 -0400)
committerLucas Bajolet <r4pass@hotmail.com>
Tue, 23 Sep 2014 18:06:22 +0000 (14:06 -0400)
Signed-off-by: Lucas Bajolet <r4pass@hotmail.com>

src/uml/uml.nit [new file with mode: 0644]
src/uml/uml_base.nit [new file with mode: 0644]
src/uml/uml_class.nit [new file with mode: 0644]

diff --git a/src/uml/uml.nit b/src/uml/uml.nit
new file mode 100644 (file)
index 0000000..2a881a9
--- /dev/null
@@ -0,0 +1,19 @@
+# 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.
+
+# Group head module for UML generation services
+module uml
+
+import uml_base
+import uml_class
diff --git a/src/uml/uml_base.nit b/src/uml/uml_base.nit
new file mode 100644 (file)
index 0000000..e54ccef
--- /dev/null
@@ -0,0 +1,38 @@
+# 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.
+
+# Exposes the base class for UML generation of a `Model`
+module uml_base
+
+import toolcontext
+import model_utils
+
+redef class ToolContext
+       # -p
+       var opt_privacy = new OptionBool("Generates private API", "-p", "--private")
+
+       # Shortcut for the value of `self.opt_privacy`
+       fun private_gen: Bool do return opt_privacy.value
+
+       redef init do
+               option_context.add_option opt_privacy
+               super
+       end
+end
+
+class UMLModel
+       var model: Model
+       var mainmodule: MModule
+       var ctx: ToolContext
+end
diff --git a/src/uml/uml_class.nit b/src/uml/uml_class.nit
new file mode 100644 (file)
index 0000000..7581f2a
--- /dev/null
@@ -0,0 +1,232 @@
+# 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.
+
+# Provides facilities of exporting a `Model` to a UML class diagram
+module uml_class
+
+import uml_base
+
+redef class UMLModel
+       # Generates a UML class diagram from a `Model`
+       fun generate_class_uml: Streamable do
+               var tpl = new Template
+               tpl.add "digraph G \{\n"
+               tpl.add """     fontname = "Bitstream Vera Sans"
+                               fontsize = 8
+                               node [
+                                       fontname = "Bitstream Vera Sans"
+                                       fontsize = 8
+                                       shape = "record"
+                               ]
+
+                               edge [
+                                       fontname = "Bitstream Vera Sans"
+                                       fontsize = 8
+                               ]\n"""
+               tpl.add model.tpl_class(ctx, mainmodule)
+               tpl.add "\}"
+               return tpl
+       end
+end
+
+redef class Model
+
+       # Generates a UML Class diagram from the entities of a `Model`
+       fun tpl_class(ctx: ToolContext, main: MModule): Streamable do
+               var t = new Template
+               for i in mclasses do
+                       if not ctx.private_gen and i.visibility != public_visibility then continue
+                       t.add i.tpl_class(ctx, main)
+                       t.add "\n"
+               end
+               return t
+       end
+
+end
+
+redef class MEntity
+       # Generates a dot-compatible `Streamable` UML Class diagram from `self`
+       fun tpl_class(ctx: ToolContext, main: MModule): Streamable is abstract
+end
+
+redef class MClass
+
+       redef fun tpl_class(ctx, main): Streamable do
+               var t = new Template
+               t.add "{name} [\n label = \"\{"
+               if kind == abstract_kind then
+                       t.add "abstract\\n{name}"
+               else if kind == interface_kind then
+                       t.add "interface\\n{name}"
+               else
+                       t.add "{name}"
+               end
+               if arity > 0 then
+                       t.add "["
+                       var formal = intro.parameter_names
+                       t.add formal.first
+                       for i in [1 .. formal.length[ do
+                               t.add ", "
+                               t.add formal[i]
+                       end
+                       t.add "]"
+               end
+               t.add "|"
+               var props: Collection[MProperty]
+               if ctx.private_gen then
+                       props = intro_mproperties(none_visibility)
+               else
+                       props = intro_mproperties(public_visibility)
+               end
+               for i in props do
+                       if i isa MAttribute then
+                               t.add i.tpl_class(ctx, main)
+                               t.add "\\l"
+                       end
+               end
+               t.add "|"
+               for i in intro_methods do
+                       if not ctx.private_gen and i.visibility != public_visibility then continue
+                       t.add i.tpl_class(ctx, main)
+                       t.add "\\l"
+               end
+               t.add "\}\"\n]\n"
+               var g = in_hierarchy(main).direct_greaters
+               for i in g do
+                       if not ctx.private_gen and i.visibility != public_visibility then continue
+                       t.add "{i.name} -> {name} [dir=back"
+                       if i.kind == interface_kind then
+                               t.add " arrowtail=open style=dashed"
+                       else
+                               t.add " arrowtail=empty"
+                       end
+                       t.add "];\n"
+               end
+               return t
+       end
+
+end
+
+redef class MMethod
+       redef fun tpl_class(ctx, main) do
+               var tpl = new Template
+               tpl.add visibility.tpl_class
+               tpl.add " "
+               tpl.add name.escape_to_dot
+               tpl.add intro.msignature.tpl_class(ctx, main)
+               return tpl
+       end
+end
+
+redef class MSignature
+
+       redef fun tpl_class(ctx, main) do
+               var t = new Template
+               t.add "("
+               var params = new Array[MParameter]
+               for i in mparameters do
+                       params.add i
+               end
+               if params.length > 0 then
+                       t.add params.first.name
+                       t.add ": "
+                       t.add params.first.mtype.tpl_class(ctx, main)
+                       for i in [1 .. params.length [ do
+                               t.add ", "
+                               t.add params[i].name
+                               t.add ": "
+                               t.add params[i].mtype.tpl_class(ctx, main)
+                       end
+               end
+               t.add ")"
+               if return_mtype != null then
+                       t.add ": "
+                       t.add return_mtype.tpl_class(ctx, main)
+               end
+               return t
+       end
+end
+
+redef class MAttribute
+       redef fun tpl_class(ctx, main) do
+               var tpl = new Template
+               tpl.add visibility.tpl_class
+               tpl.add " "
+               tpl.add name
+               tpl.add ": "
+               tpl.add intro.static_mtype.tpl_class(ctx, main)
+               return tpl
+       end
+end
+
+redef class MVisibility
+       # Returns the visibility as a UML token
+       #
+       #    assert public_visibility.tpl_class == "+"
+       #    assert private_visibility.tpl_class == "-"
+       fun tpl_class: Streamable do
+               if self == private_visibility then
+                       return "-"
+               else if self == protected_visibility then
+                       return "#"
+               else if self == public_visibility then
+                       return "+"
+               else
+                       return "+"
+               end
+       end
+end
+
+redef class MClassType
+       redef fun tpl_class(c, m) do
+               return name
+       end
+end
+
+redef class MGenericType
+       redef fun tpl_class(c, m) do
+               var t = new Template
+               t.add name.substring(0, name.index_of('['))
+               t.add "["
+               t.add arguments.first.tpl_class(c, m)
+               for i in [1 .. arguments.length[ do
+                       t.add ", "
+                       t.add arguments[i].tpl_class(c, m)
+               end
+               t.add "]"
+               return t
+       end
+end
+
+redef class MParameterType
+       redef fun tpl_class(c, m) do
+               var n = mclass.intro.parameter_names
+               return n[rank]
+       end
+end
+
+redef class MVirtualType
+       redef fun tpl_class(c, m) do
+               return name
+       end
+end
+
+redef class MNullableType
+       redef fun tpl_class(c, m) do
+               var t = new Template
+               t.add "nullable "
+               t.add mtype.tpl_class(c, m)
+               return t
+       end
+end