Class: Metanorma::Datamodel::PlantumlRenderer

Inherits:
Object
  • Object
show all
Defined in:
lib/metanorma/standoc/datamodel/plantuml_renderer.rb

Constant Summary collapse

TEMPLATES_PATH =
File.expand_path("../views/datamodel", __dir__).freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(yml, plantuml_path) ⇒ PlantumlRenderer

Returns a new instance of PlantumlRenderer.



12
13
14
15
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 12

def initialize(yml, plantuml_path)
  @yml = yml
  @plantuml_path = plantuml_path
end

Instance Attribute Details

#plantuml_pathObject (readonly)

Returns the value of attribute plantuml_path.



10
11
12
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 10

def plantuml_path
  @plantuml_path
end

#ymlObject (readonly)

Returns the value of attribute yml.



10
11
12
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 10

def yml
  @yml
end

Instance Method Details

#attribute_cardinality(attribute_cardinality) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 281

def attribute_cardinality(attribute_cardinality)
  cardinality = ""
  if attribute_cardinality
    cardinality = attribute_cardinality_plantuml(
      attribute_cardinality,
      false,
    )
    cardinality = " #{cardinality}"
  end
  cardinality
end

#attribute_cardinality_plantuml(cardinality, with_bracket = true) ⇒ Object



145
146
147
148
149
150
151
152
153
154
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 145

def attribute_cardinality_plantuml(cardinality, with_bracket = true)
  return "" if cardinality.nil? ||
    (cardinality["min"] == cardinality["max"] &&
      cardinality["min"] == 1)

  card = "#{cardinality['min']}..#{cardinality['max']}"
  return card unless with_bracket

  "[#{card}]"
end

#attribute_to_plantuml(attr_name, attr_hash) ⇒ Object



139
140
141
142
143
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 139

def attribute_to_plantuml(attr_name, attr_hash)
  <<~TEMPLATE
    +#{attr_name}: #{attr_hash['type']}#{attribute_cardinality_plantuml(attr_hash['cardinality'])}
  TEMPLATE
end

#attributes_to_plantuml(attributes) ⇒ Object



131
132
133
134
135
136
137
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 131

def attributes_to_plantuml(attributes)
  return unless attributes

  attributes.map do |(attr_name, attr_hash)|
    attribute_to_plantuml(attr_name, attr_hash)
  end.join("").sub(/\n\Z/, "")
end

#bottom_to_plantuml(bottom) ⇒ Object



346
347
348
349
350
351
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 346

def bottom_to_plantuml(bottom)
  bottom ||= []
  return if bottom.empty?

  "#{bottom.join("\n")}\n"
end

#bottom_yml_to_plantumlObject



88
89
90
91
92
93
94
95
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 88

def bottom_yml_to_plantuml
  return if empty?(yml, "bottom")

  <<~TEMPLATE
    '******* BOTTOM OVERRIDE CONFIG **************************************
    #{join_as_plantuml(bottom_to_plantuml(yml['bottom']))}
  TEMPLATE
end

#class_defs_yml_to_plantumlObject



42
43
44
45
46
47
48
49
50
51
52
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 42

def class_defs_yml_to_plantuml
  return if empty?(yml, "classes") && empty?(yml, "enums")

  <<~TEMPLATE
    '******* CLASS DEFINITIONS ********************************************
    #{join_as_plantuml(
      classes_to_classes_plantuml(yml['classes']),
      enums_to_enums_plantuml(yml['enums']),
    )}
  TEMPLATE
end

#class_groups_yml_to_plantumlObject



54
55
56
57
58
59
60
61
62
63
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 54

def class_groups_yml_to_plantuml
  return if empty?(yml, "groups")

  <<~TEMPLATE
    '******* CLASS GROUPS *************************************************
    #{join_as_plantuml(
      groups_to_plantuml(yml['groups']),
    )}
  TEMPLATE
end

#class_relations_yml_to_plantumlObject



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 65

def class_relations_yml_to_plantuml
  return if empty?(yml, "classes") && empty?(yml, "relations")

  <<~TEMPLATE
    '******* CLASS RELATIONS **********************************************
    #{join_as_plantuml(
      classes_to_relations_plantuml(yml['classes']),
      relations_to_plantuml(nil, yml['relations']),
    )}
  TEMPLATE
end

#class_to_plantuml(class_name, class_hash) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 116

def class_to_plantuml(class_name, class_hash)
  return unless class_name

  class_hash ||= {}

  <<~TEMPLATE
    class #{class_name}#{model_stereotype_to_plantuml(class_hash['type'])} {
    #{join_as_plantuml(
      attributes_to_plantuml(class_hash['attributes']),
      constraints_to_plantuml(class_hash['constraints']),
    )}
    }
  TEMPLATE
end

#classes_to_classes_plantuml(classes) ⇒ Object



106
107
108
109
110
111
112
113
114
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 106

def classes_to_classes_plantuml(classes)
  classes ||= {}

  return if classes.empty?

  classes.map do |(class_name, class_hash)|
    class_to_plantuml(class_name, class_hash)
  end.join("\n")
end

#classes_to_relations_plantuml(classes) ⇒ Object



173
174
175
176
177
178
179
180
181
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 173

def classes_to_relations_plantuml(classes)
  output_ary = classes.map do |(class_name, class_hash)|
    class_hash ||= {}
    relations = class_hash["relations"]
    relations_to_plantuml(class_name, relations)
  end

  join_as_plantuml(*output_ary)
end

#constraints_to_plantuml(constraints) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 156

def constraints_to_plantuml(constraints)
  constraints ||= []

  return if constraints.empty?

  constraints_output = constraints.map do |constraint|
    "  {#{constraint}}"
  end

  <<~TEMPLATE
      __ constraints __
    #{join_as_plantuml(
      *constraints_output,
    )}
  TEMPLATE
end

#diagram_captionObject



29
30
31
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 29

def diagram_caption
  yml["caption"]
end

#diagram_options_to_plantuml(diagram_options) ⇒ Object



339
340
341
342
343
344
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 339

def diagram_options_to_plantuml(diagram_options)
  diagram_options ||= []
  return if diagram_options.empty?

  "#{diagram_options.join("\n")}\n"
end

#diagram_options_yml_to_plantumlObject



77
78
79
80
81
82
83
84
85
86
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 77

def diagram_options_yml_to_plantuml
  return if empty?(yml, "diagram_options")

  <<~TEMPLATE
    '******* DIAGRAM SPECIFIC CONFIG **************************************
    #{join_as_plantuml(
      diagram_options_to_plantuml(yml['diagram_options']),
    )}
  TEMPLATE
end

#empty?(yml, prop) ⇒ Boolean

Returns:

  • (Boolean)


404
405
406
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 404

def empty?(yml, prop)
  yml[prop].nil? || yml[prop].length.zero?
end

#enum_to_plantuml(enum_name, enum_hash) ⇒ Object



301
302
303
304
305
306
307
308
309
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 301

def enum_to_plantuml(enum_name, enum_hash)
  enum_hash ||= {}

  <<~TEMPLATE
    enum #{enum_name}#{model_stereotype_to_plantuml(enum_hash['type'])} {
    #{join_as_plantuml(enum_values_to_plantuml(enum_hash['values']))}
    }
  TEMPLATE
end

#enum_values_to_plantuml(enum_values) ⇒ Object



317
318
319
320
321
322
323
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 317

def enum_values_to_plantuml(enum_values)
  output_ary = enum_values.map do |(enum_value, _enum_value_hash)|
    "  #{enum_value}"
  end

  join_as_plantuml(*output_ary)
end

#enums_to_enums_plantuml(enums) ⇒ Object



293
294
295
296
297
298
299
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 293

def enums_to_enums_plantuml(enums)
  enums ||= {}

  enums.map do |(enum_name, enum_hash)|
    enum_to_plantuml(enum_name, enum_hash)
  end.join("\n\n")
end

#fidelity_to_plantuml(fidelity) ⇒ Object



395
396
397
398
399
400
401
402
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 395

def fidelity_to_plantuml(fidelity)
  return "" if fidelity.nil?

  output = ""
  output += hide_other_classes(fidelity) if fidelity["hideOtherClasses"]
  output += "\nhide members\n" if fidelity["hideMembers"]
  output
end

#fidelity_yml_to_plantumlObject



97
98
99
100
101
102
103
104
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 97

def fidelity_yml_to_plantuml
  return if empty?(yml, "fidelity")

  <<~TEMPLATE
    '******* FIDELITY *****************************************************
    #{join_as_plantuml(fidelity_to_plantuml(yml['fidelity']))}
  TEMPLATE
end

#format_association_relation(relation, fidelity_classes, acc) ⇒ Object



370
371
372
373
374
375
376
377
378
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 370

def format_association_relation(relation, fidelity_classes, acc)
  return unless relation["relationship"] &&
    relation["relationship"]["association"]

  association = relation["relationship"]["association"]
  return unless association && !fidelity_classes.key?(association)

  acc.merge!(association => true)
end

#format_hidden_class(accum, fidelity_classes, class_hash) ⇒ Object



353
354
355
356
357
358
359
360
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 353

def format_hidden_class(accum, fidelity_classes, class_hash)
  return accum if class_hash["relations"].nil?

  class_hash["relations"].each_with_object(accum) do |relation, acc|
    format_source_target_relation(relation, fidelity_classes, acc)
    format_association_relation(relation, fidelity_classes, acc)
  end
end

#format_source_target_relation(relation, fidelity_classes, acc) ⇒ Object



362
363
364
365
366
367
368
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 362

def format_source_target_relation(relation, fidelity_classes, acc)
  %w[source target].each do |type|
    next unless relation[type] && !fidelity_classes.key?(relation[type])

    acc.merge!(relation[type] => true)
  end
end

#groups_to_plantuml(groups) ⇒ Object



325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 325

def groups_to_plantuml(groups)
  groups ||= []
  return if groups.empty?

  groups.reduce("") do |output, group|
    output += "\ntogether {\n"
    group.each do |class_name|
      output += "\nclass #{class_name}\n"
    end
    output += "\n}\n"
    output
  end
end

#hide_other_classes(fidelity) ⇒ Object



380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 380

def hide_other_classes(fidelity)
  return "" if fidelity.nil? || fidelity["classes"].nil?

  output = ""
  hidden_classes = fidelity["classes"]
    .reduce({}) do |acc, (_class_name, class_hash)|
    format_hidden_class(acc, fidelity["classes"], class_hash)
  end

  hidden_classes.each_key do |hidden_class_name|
    output += "\nhide #{hidden_class_name}\n"
  end
  output
end

#imports_yml_to_plantumlObject



33
34
35
36
37
38
39
40
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 33

def imports_yml_to_plantuml
  return if empty?(yml, "imports")

  <<~TEMPLATE
    '******* IMPORTS ******************************************************
    !include #{plantuml_path}/style.uml.inc
  TEMPLATE
end

#join_as_plantuml(*ary) ⇒ Object



17
18
19
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 17

def join_as_plantuml(*ary)
  ary.compact.join("\n").sub(/(?<!\s)\s+\Z/, "")
end

#model_stereotype_to_plantuml(model_stereotype) ⇒ Object



311
312
313
314
315
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 311

def model_stereotype_to_plantuml(model_stereotype)
  return "" unless model_stereotype

  " <<#{model_stereotype}>>"
end

#relation_arrow(relationship, relation) ⇒ Object



196
197
198
199
200
201
202
203
204
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 196

def relation_arrow(relationship, relation)
  [
    relationship_type_to_plantuml("source",
                                  relationship["source"]["type"]),
    (relation["direction"]).to_s,
    relationship_type_to_plantuml("target",
                                  relationship["target"]["type"]),
  ].compact.join("-")
end

#relation_association(source, target, association) ⇒ Object



236
237
238
239
240
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 236

def relation_association(source, target, association)
  return unless association

  "\n(#{source}, #{target}) . #{association}"
end

#relation_label(action) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 206

def relation_label(action)
  return "" unless action

  case action["direction"]
  when "source"
    " : < #{action['verb']}"
  when "target"
    " : #{action['verb']} >"
  else
    ""
  end
end

#relation_output_lines(source, target, relation, relationship) ⇒ Object



249
250
251
252
253
254
255
256
257
258
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 249

def relation_output_lines(source, target, relation, relationship)
  output_lines = [
    source_arrow_end(source, relationship),
    relation_arrow(relationship, relation),
    target_arrow_end(target, relationship, relation["action"]),
    relation_association(source, target, relationship["association"]),
  ].join(" ")

  join_as_plantuml(*output_lines)
end

#relation_to_plantuml(source, target, relation) ⇒ Object



242
243
244
245
246
247
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 242

def relation_to_plantuml(source, target, relation)
  relationship = relation["relationship"] || {}
  relationship["source"] ||= {}
  relationship["target"] ||= {}
  relation_output_lines(source, target, relation, relationship)
end

#relations_to_plantuml(class_name, relations) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 183

def relations_to_plantuml(class_name, relations)
  return unless relations

  output_ary = relations.map do |relation|
    source = class_name || relation["source"]
    relation_to_plantuml(source,
                         relation["target"],
                         relation)
  end

  join_as_plantuml(*output_ary)
end

#relationship_cardinality_to_plantuml(attribute) ⇒ Object



271
272
273
274
275
276
277
278
279
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 271

def relationship_cardinality_to_plantuml(attribute)
  attribute_name = (attribute || {}).keys.first

  return unless attribute_name

  attribute_hash = attribute[attribute_name] || {}
  card = attribute_cardinality(attribute_hash["cardinality"])
  "\"+#{attribute_name}#{card}\""
end

#relationship_type_to_plantuml(relation_end, relationship_type) ⇒ Object



260
261
262
263
264
265
266
267
268
269
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 260

def relationship_type_to_plantuml(relation_end, relationship_type)
  is_source = (relation_end == "source")
  mappings = {
    "direct" => is_source ? "<" : ">",
    "inheritance" => is_source ? "<|" : "|>",
    "composition" => "*",
    "aggregation" => "o",
  }
  mappings.fetch(relationship_type, "")
end

#renderObject



21
22
23
24
25
26
27
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 21

def render
  ERB.new(
    File.read(
      File.join(TEMPLATES_PATH, "plantuml_representation.adoc.erb"),
    ),
  ).result(binding)
end

#source_arrow_end(source, relationship) ⇒ Object



219
220
221
222
223
224
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 219

def source_arrow_end(source, relationship)
  source_attribute = relationship_cardinality_to_plantuml(
    relationship["source"]["attribute"],
  )
  [source, source_attribute].join(" ")
end

#target_arrow_end(target, relationship, action) ⇒ Object



226
227
228
229
230
231
232
233
234
# File 'lib/metanorma/standoc/datamodel/plantuml_renderer.rb', line 226

def target_arrow_end(target, relationship, action)
  target_attribute = relationship_cardinality_to_plantuml(
    relationship["target"]["attribute"],
  )
  [
    [target_attribute, target].join(" "),
    relation_label(action),
  ].join
end