uml: Added UML class diagram generation from a Nit model
[nit.git] / src / uml / uml_class.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Provides facilities of exporting a `Model` to a UML class diagram
16 module uml_class
17
18 import uml_base
19
20 redef class UMLModel
21 # Generates a UML class diagram from a `Model`
22 fun generate_class_uml: Streamable do
23 var tpl = new Template
24 tpl.add "digraph G \{\n"
25 tpl.add """ fontname = "Bitstream Vera Sans"
26 fontsize = 8
27 node [
28 fontname = "Bitstream Vera Sans"
29 fontsize = 8
30 shape = "record"
31 ]
32
33 edge [
34 fontname = "Bitstream Vera Sans"
35 fontsize = 8
36 ]\n"""
37 tpl.add model.tpl_class(ctx, mainmodule)
38 tpl.add "\}"
39 return tpl
40 end
41 end
42
43 redef class Model
44
45 # Generates a UML Class diagram from the entities of a `Model`
46 fun tpl_class(ctx: ToolContext, main: MModule): Streamable do
47 var t = new Template
48 for i in mclasses do
49 if not ctx.private_gen and i.visibility != public_visibility then continue
50 t.add i.tpl_class(ctx, main)
51 t.add "\n"
52 end
53 return t
54 end
55
56 end
57
58 redef class MEntity
59 # Generates a dot-compatible `Streamable` UML Class diagram from `self`
60 fun tpl_class(ctx: ToolContext, main: MModule): Streamable is abstract
61 end
62
63 redef class MClass
64
65 redef fun tpl_class(ctx, main): Streamable do
66 var t = new Template
67 t.add "{name} [\n label = \"\{"
68 if kind == abstract_kind then
69 t.add "abstract\\n{name}"
70 else if kind == interface_kind then
71 t.add "interface\\n{name}"
72 else
73 t.add "{name}"
74 end
75 if arity > 0 then
76 t.add "["
77 var formal = intro.parameter_names
78 t.add formal.first
79 for i in [1 .. formal.length[ do
80 t.add ", "
81 t.add formal[i]
82 end
83 t.add "]"
84 end
85 t.add "|"
86 var props: Collection[MProperty]
87 if ctx.private_gen then
88 props = intro_mproperties(none_visibility)
89 else
90 props = intro_mproperties(public_visibility)
91 end
92 for i in props do
93 if i isa MAttribute then
94 t.add i.tpl_class(ctx, main)
95 t.add "\\l"
96 end
97 end
98 t.add "|"
99 for i in intro_methods do
100 if not ctx.private_gen and i.visibility != public_visibility then continue
101 t.add i.tpl_class(ctx, main)
102 t.add "\\l"
103 end
104 t.add "\}\"\n]\n"
105 var g = in_hierarchy(main).direct_greaters
106 for i in g do
107 if not ctx.private_gen and i.visibility != public_visibility then continue
108 t.add "{i.name} -> {name} [dir=back"
109 if i.kind == interface_kind then
110 t.add " arrowtail=open style=dashed"
111 else
112 t.add " arrowtail=empty"
113 end
114 t.add "];\n"
115 end
116 return t
117 end
118
119 end
120
121 redef class MMethod
122 redef fun tpl_class(ctx, main) do
123 var tpl = new Template
124 tpl.add visibility.tpl_class
125 tpl.add " "
126 tpl.add name.escape_to_dot
127 tpl.add intro.msignature.tpl_class(ctx, main)
128 return tpl
129 end
130 end
131
132 redef class MSignature
133
134 redef fun tpl_class(ctx, main) do
135 var t = new Template
136 t.add "("
137 var params = new Array[MParameter]
138 for i in mparameters do
139 params.add i
140 end
141 if params.length > 0 then
142 t.add params.first.name
143 t.add ": "
144 t.add params.first.mtype.tpl_class(ctx, main)
145 for i in [1 .. params.length [ do
146 t.add ", "
147 t.add params[i].name
148 t.add ": "
149 t.add params[i].mtype.tpl_class(ctx, main)
150 end
151 end
152 t.add ")"
153 if return_mtype != null then
154 t.add ": "
155 t.add return_mtype.tpl_class(ctx, main)
156 end
157 return t
158 end
159 end
160
161 redef class MAttribute
162 redef fun tpl_class(ctx, main) do
163 var tpl = new Template
164 tpl.add visibility.tpl_class
165 tpl.add " "
166 tpl.add name
167 tpl.add ": "
168 tpl.add intro.static_mtype.tpl_class(ctx, main)
169 return tpl
170 end
171 end
172
173 redef class MVisibility
174 # Returns the visibility as a UML token
175 #
176 # assert public_visibility.tpl_class == "+"
177 # assert private_visibility.tpl_class == "-"
178 fun tpl_class: Streamable do
179 if self == private_visibility then
180 return "-"
181 else if self == protected_visibility then
182 return "#"
183 else if self == public_visibility then
184 return "+"
185 else
186 return "+"
187 end
188 end
189 end
190
191 redef class MClassType
192 redef fun tpl_class(c, m) do
193 return name
194 end
195 end
196
197 redef class MGenericType
198 redef fun tpl_class(c, m) do
199 var t = new Template
200 t.add name.substring(0, name.index_of('['))
201 t.add "["
202 t.add arguments.first.tpl_class(c, m)
203 for i in [1 .. arguments.length[ do
204 t.add ", "
205 t.add arguments[i].tpl_class(c, m)
206 end
207 t.add "]"
208 return t
209 end
210 end
211
212 redef class MParameterType
213 redef fun tpl_class(c, m) do
214 var n = mclass.intro.parameter_names
215 return n[rank]
216 end
217 end
218
219 redef class MVirtualType
220 redef fun tpl_class(c, m) do
221 return name
222 end
223 end
224
225 redef class MNullableType
226 redef fun tpl_class(c, m) do
227 var t = new Template
228 t.add "nullable "
229 t.add mtype.tpl_class(c, m)
230 return t
231 end
232 end