From e5dad75d0c378b23fb5d01653766bb524983b091 Mon Sep 17 00:00:00 2001 From: Lucas Bajolet Date: Wed, 17 Sep 2014 16:12:49 -0400 Subject: [PATCH] uml: Added UML class diagram generation from a Nit model Signed-off-by: Lucas Bajolet --- src/uml/uml.nit | 19 ++++ src/uml/uml_base.nit | 38 ++++++++ src/uml/uml_class.nit | 232 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 src/uml/uml.nit create mode 100644 src/uml/uml_base.nit create mode 100644 src/uml/uml_class.nit diff --git a/src/uml/uml.nit b/src/uml/uml.nit new file mode 100644 index 0000000..2a881a9 --- /dev/null +++ b/src/uml/uml.nit @@ -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 index 0000000..e54ccef --- /dev/null +++ b/src/uml/uml_base.nit @@ -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 index 0000000..7581f2a --- /dev/null +++ b/src/uml/uml_class.nit @@ -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 -- 1.7.9.5