metanorma-standoc 1.11.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +3 -31
  3. data/.gitignore +23 -0
  4. data/lib/asciidoctor/standoc/base.rb +2 -145
  5. data/lib/asciidoctor/standoc/blocks.rb +2 -238
  6. data/lib/asciidoctor/standoc/blocks_notes.rb +2 -100
  7. data/lib/asciidoctor/standoc/cleanup.rb +2 -208
  8. data/lib/asciidoctor/standoc/cleanup_amend.rb +2 -53
  9. data/lib/asciidoctor/standoc/cleanup_block.rb +2 -172
  10. data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +2 -212
  11. data/lib/asciidoctor/standoc/cleanup_footnotes.rb +2 -108
  12. data/lib/asciidoctor/standoc/cleanup_image.rb +2 -69
  13. data/lib/asciidoctor/standoc/cleanup_inline.rb +2 -189
  14. data/lib/asciidoctor/standoc/cleanup_maths.rb +2 -221
  15. data/lib/asciidoctor/standoc/cleanup_ref.rb +2 -169
  16. data/lib/asciidoctor/standoc/cleanup_ref_dl.rb +2 -103
  17. data/lib/asciidoctor/standoc/cleanup_reqt.rb +2 -110
  18. data/lib/asciidoctor/standoc/cleanup_section.rb +2 -184
  19. data/lib/asciidoctor/standoc/cleanup_section_names.rb +2 -91
  20. data/lib/asciidoctor/standoc/cleanup_symbols.rb +2 -47
  21. data/lib/asciidoctor/standoc/cleanup_table.rb +2 -67
  22. data/lib/asciidoctor/standoc/cleanup_terms.rb +2 -139
  23. data/lib/asciidoctor/standoc/cleanup_terms_designations.rb +2 -198
  24. data/lib/asciidoctor/standoc/cleanup_text.rb +2 -95
  25. data/lib/asciidoctor/standoc/cleanup_toc.rb +3 -0
  26. data/lib/asciidoctor/standoc/cleanup_xref.rb +2 -106
  27. data/lib/asciidoctor/standoc/converter.rb +2 -123
  28. data/lib/asciidoctor/standoc/datamodel/attributes_table_preprocessor.rb +2 -56
  29. data/lib/asciidoctor/standoc/datamodel/diagram_preprocessor.rb +2 -102
  30. data/lib/asciidoctor/standoc/datamodel/plantuml_renderer.rb +3 -404
  31. data/lib/asciidoctor/standoc/deprecated.rb +5 -0
  32. data/lib/asciidoctor/standoc/front.rb +2 -223
  33. data/lib/asciidoctor/standoc/front_contributor.rb +2 -191
  34. data/lib/asciidoctor/standoc/inline.rb +2 -231
  35. data/lib/asciidoctor/standoc/lists.rb +2 -119
  36. data/lib/asciidoctor/standoc/macros.rb +2 -203
  37. data/lib/asciidoctor/standoc/macros_form.rb +2 -62
  38. data/lib/asciidoctor/standoc/macros_note.rb +2 -44
  39. data/lib/asciidoctor/standoc/macros_plantuml.rb +2 -112
  40. data/lib/asciidoctor/standoc/macros_terms.rb +2 -180
  41. data/lib/asciidoctor/standoc/ref.rb +2 -251
  42. data/lib/asciidoctor/standoc/ref_sect.rb +2 -153
  43. data/lib/asciidoctor/standoc/ref_utility.rb +2 -0
  44. data/lib/asciidoctor/standoc/render.rb +2 -114
  45. data/lib/asciidoctor/standoc/reqt.rb +2 -89
  46. data/lib/asciidoctor/standoc/section.rb +2 -207
  47. data/lib/asciidoctor/standoc/table.rb +2 -84
  48. data/lib/asciidoctor/standoc/term_lookup_cleanup.rb +2 -178
  49. data/lib/asciidoctor/standoc/terms.rb +2 -159
  50. data/lib/asciidoctor/standoc/utils.rb +2 -100
  51. data/lib/asciidoctor/standoc/validate.rb +2 -157
  52. data/lib/asciidoctor/standoc/validate_section.rb +2 -54
  53. data/lib/metanorma/standoc/base.rb +149 -0
  54. data/lib/{asciidoctor → metanorma}/standoc/basicdoc.rng +0 -0
  55. data/lib/{asciidoctor → metanorma}/standoc/biblio.rng +0 -0
  56. data/lib/metanorma/standoc/blocks.rb +239 -0
  57. data/lib/metanorma/standoc/blocks_notes.rb +101 -0
  58. data/lib/metanorma/standoc/cleanup.rb +146 -0
  59. data/lib/metanorma/standoc/cleanup_amend.rb +54 -0
  60. data/lib/metanorma/standoc/cleanup_block.rb +173 -0
  61. data/lib/metanorma/standoc/cleanup_boilerplate.rb +213 -0
  62. data/lib/metanorma/standoc/cleanup_footnotes.rb +109 -0
  63. data/lib/metanorma/standoc/cleanup_image.rb +70 -0
  64. data/lib/metanorma/standoc/cleanup_inline.rb +190 -0
  65. data/lib/metanorma/standoc/cleanup_maths.rb +222 -0
  66. data/lib/metanorma/standoc/cleanup_ref.rb +170 -0
  67. data/lib/metanorma/standoc/cleanup_ref_dl.rb +104 -0
  68. data/lib/metanorma/standoc/cleanup_reqt.rb +111 -0
  69. data/lib/metanorma/standoc/cleanup_section.rb +212 -0
  70. data/lib/metanorma/standoc/cleanup_section_names.rb +92 -0
  71. data/lib/metanorma/standoc/cleanup_symbols.rb +48 -0
  72. data/lib/metanorma/standoc/cleanup_table.rb +68 -0
  73. data/lib/metanorma/standoc/cleanup_terms.rb +140 -0
  74. data/lib/metanorma/standoc/cleanup_terms_designations.rb +199 -0
  75. data/lib/metanorma/standoc/cleanup_text.rb +96 -0
  76. data/lib/metanorma/standoc/cleanup_toc.rb +98 -0
  77. data/lib/metanorma/standoc/cleanup_xref.rb +107 -0
  78. data/lib/metanorma/standoc/converter.rb +124 -0
  79. data/lib/metanorma/standoc/datamodel/attributes_table_preprocessor.rb +57 -0
  80. data/lib/metanorma/standoc/datamodel/diagram_preprocessor.rb +103 -0
  81. data/lib/metanorma/standoc/datamodel/plantuml_renderer.rb +409 -0
  82. data/lib/metanorma/standoc/front.rb +224 -0
  83. data/lib/metanorma/standoc/front_contributor.rb +192 -0
  84. data/lib/metanorma/standoc/inline.rb +232 -0
  85. data/lib/{asciidoctor → metanorma}/standoc/isodoc.rng +29 -0
  86. data/lib/metanorma/standoc/lists.rb +120 -0
  87. data/lib/metanorma/standoc/macros.rb +204 -0
  88. data/lib/metanorma/standoc/macros_form.rb +63 -0
  89. data/lib/metanorma/standoc/macros_note.rb +45 -0
  90. data/lib/metanorma/standoc/macros_plantuml.rb +113 -0
  91. data/lib/metanorma/standoc/macros_terms.rb +181 -0
  92. data/lib/metanorma/standoc/ref.rb +243 -0
  93. data/lib/metanorma/standoc/ref_sect.rb +153 -0
  94. data/lib/{asciidoctor/standoc/ref_date_id.rb → metanorma/standoc/ref_utility.rb} +43 -5
  95. data/lib/metanorma/standoc/render.rb +115 -0
  96. data/lib/metanorma/standoc/reqt.rb +90 -0
  97. data/lib/{asciidoctor → metanorma}/standoc/reqt.rng +0 -0
  98. data/lib/metanorma/standoc/section.rb +209 -0
  99. data/lib/metanorma/standoc/table.rb +85 -0
  100. data/lib/metanorma/standoc/term_lookup_cleanup.rb +179 -0
  101. data/lib/metanorma/standoc/terms.rb +160 -0
  102. data/lib/metanorma/standoc/utils.rb +101 -0
  103. data/lib/metanorma/standoc/validate.rb +158 -0
  104. data/lib/metanorma/standoc/validate_section.rb +55 -0
  105. data/lib/metanorma/standoc/version.rb +1 -1
  106. data/lib/{asciidoctor → metanorma}/standoc/views/datamodel/model_representation.adoc.erb +0 -0
  107. data/lib/{asciidoctor → metanorma}/standoc/views/datamodel/plantuml_representation.adoc.erb +0 -0
  108. data/lib/metanorma-standoc.rb +1 -1
  109. data/metanorma-standoc.gemspec +1 -1
  110. data/spec/{asciidoctor → metanorma}/base_spec.rb +27 -10
  111. data/spec/{asciidoctor → metanorma}/blank_spec.rb +1 -1
  112. data/spec/{asciidoctor → metanorma}/blocks_spec.rb +1 -1
  113. data/spec/{asciidoctor → metanorma}/cleanup_blocks_spec.rb +1 -1
  114. data/spec/{asciidoctor → metanorma}/cleanup_sections_spec.rb +1 -1
  115. data/spec/{asciidoctor → metanorma}/cleanup_spec.rb +5 -5
  116. data/spec/{asciidoctor → metanorma}/cleanup_terms_spec.rb +2 -2
  117. data/spec/{asciidoctor → metanorma}/datamodel/attributes_table_preprocessor_spec.rb +1 -1
  118. data/spec/{asciidoctor → metanorma}/datamodel/diagram_preprocessor_spec.rb +1 -1
  119. data/spec/{asciidoctor → metanorma}/inline_spec.rb +1 -1
  120. data/spec/{asciidoctor → metanorma}/isobib_cache_spec.rb +1 -1
  121. data/spec/{asciidoctor → metanorma}/lists_spec.rb +1 -1
  122. data/spec/{asciidoctor → metanorma}/macros_json2text_spec.rb +0 -0
  123. data/spec/{asciidoctor → metanorma}/macros_plantuml_spec.rb +3 -3
  124. data/spec/{asciidoctor → metanorma}/macros_spec.rb +6 -6
  125. data/spec/{asciidoctor → metanorma}/macros_yaml2text_spec.rb +0 -0
  126. data/spec/metanorma/refs_dl_spec.rb +863 -0
  127. data/spec/{asciidoctor → metanorma}/refs_spec.rb +399 -25
  128. data/spec/{asciidoctor → metanorma}/section_spec.rb +42 -17
  129. data/spec/{asciidoctor → metanorma}/table_spec.rb +1 -1
  130. data/spec/{asciidoctor → metanorma}/validate_spec.rb +2 -2
  131. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +42 -42
  132. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec1.yml +11 -11
  133. data/spec/vcr_cassettes/isobib_get_123.yml +12 -12
  134. data/spec/vcr_cassettes/isobib_get_123_1.yml +21 -21
  135. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +81 -81
  136. data/spec/vcr_cassettes/isobib_get_123_2001.yml +10 -10
  137. data/spec/vcr_cassettes/isobib_get_124.yml +11 -11
  138. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +13 -13
  139. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +46 -46
  140. metadata +82 -32
  141. data/spec/asciidoctor/refs_dl_spec.rb +0 -864
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "metanorma/standoc/datamodel/plantuml_renderer"
5
+
6
+ module Metanorma
7
+ module Standoc
8
+ module Datamodel
9
+ class DiagramPreprocessor < Asciidoctor::Extensions::Preprocessor
10
+ BLOCK_START_REGEXP = /\{(.+?)\.\*,(.+),(.+)\}/.freeze
11
+ BLOCK_END_REGEXP = /\A\{[A-Z]+\}\z/.freeze
12
+ MARCO_REGEXP = /\[datamodel_diagram,([^,]+),?(.+)?\]/.freeze
13
+ TEMPLATES_PATH = File.expand_path("../views/datamodel", __dir__).freeze
14
+ # search document for block `datamodel_diagram`
15
+ # read include derectives that goes after that in block and transform
16
+ # into plantuml block
17
+ def process(document, reader)
18
+ input_lines = reader.readlines.to_enum
19
+ Asciidoctor::Reader.new(processed_lines(document, input_lines))
20
+ end
21
+
22
+ private
23
+
24
+ def processed_lines(document, input_lines)
25
+ input_lines.each_with_object([]) do |line, result|
26
+ if match = line.match(MARCO_REGEXP)
27
+ result
28
+ .push(*parse_datamodel_marco(match[1], match[2], document))
29
+ else
30
+ result.push(line)
31
+ end
32
+ end
33
+ end
34
+
35
+ def parse_datamodel_marco(yaml_path, include_path, document)
36
+ include_path ||= File.join(File.dirname(yaml_path), "..", "models")
37
+ include_path = yaml_relative_path(include_path, document)
38
+ yaml_relative_to_doc_path = yaml_relative_path(yaml_path, document)
39
+ view_hash = YAML.safe_load(File.read(yaml_relative_to_doc_path))
40
+ plantuml_representations(view_hash,
41
+ yaml_relative_to_doc_path,
42
+ include_path)
43
+ end
44
+
45
+ def yaml_relative_path(file_path, document)
46
+ docfile = document.attributes["docfile"] || "."
47
+ docfile_directory = File.dirname(docfile)
48
+ document.path_resolver.system_path(file_path, docfile_directory)
49
+ end
50
+
51
+ def import_format(include_path, import_name, values)
52
+ include_content = File.read(File.join(
53
+ include_path,
54
+ "#{import_name}.yml",
55
+ ))
56
+ content = YAML.safe_load(include_content)
57
+ if values
58
+ content["skipSection"] = values["skipSection"]
59
+ end
60
+ content
61
+ end
62
+
63
+ def format_import_directives(imports, include_path)
64
+ imports
65
+ .each_with_object({}) do |(import_name, values), res|
66
+ full_model_name = import_name.split("/").join
67
+ content = import_format(include_path, import_name, values)
68
+ res[content["name"] || full_model_name] = content
69
+ end.compact
70
+ end
71
+
72
+ def prepare_view_hash(view_hash, all_imports)
73
+ view_hash.merge!(
74
+ "classes" => model_type(all_imports, "class"),
75
+ "enums" => model_type(all_imports, "enum"),
76
+ "relations" => view_hash["relations"] || [],
77
+ "fidelity" => (view_hash["fidelity"] || {})
78
+ .merge!("classes" => model_type(all_imports,
79
+ "class")),
80
+ )
81
+ end
82
+
83
+ def model_type(imports, type)
84
+ imports
85
+ .select do |_name, elem|
86
+ elem["modelType"] == type
87
+ end
88
+ end
89
+
90
+ def plantuml_representations(view_hash, view_path, include_path)
91
+ yaml_directory = File.dirname(view_path)
92
+ all_imports = format_import_directives(view_hash["imports"],
93
+ include_path)
94
+ prepare_view_hash(view_hash, all_imports)
95
+ Metanorma::Datamodel::PlantumlRenderer
96
+ .new(view_hash, File.join(yaml_directory, ".."))
97
+ .render
98
+ .split("\n")
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,409 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module Metanorma
6
+ module Datamodel
7
+ class PlantumlRenderer
8
+ TEMPLATES_PATH = File.expand_path("../views/datamodel", __dir__).freeze
9
+
10
+ attr_reader :yml, :plantuml_path
11
+
12
+ def initialize(yml, plantuml_path)
13
+ @yml = yml
14
+ @plantuml_path = plantuml_path
15
+ end
16
+
17
+ def join_as_plantuml(*ary)
18
+ ary.compact.join("\n").sub(/\s+\Z/, "")
19
+ end
20
+
21
+ def render
22
+ ERB.new(
23
+ File.read(
24
+ File.join(TEMPLATES_PATH, "plantuml_representation.adoc.erb")
25
+ )
26
+ ).result(binding)
27
+ end
28
+
29
+ def diagram_caption
30
+ yml["caption"]
31
+ end
32
+
33
+ def imports_yml_to_plantuml
34
+ return if empty?(yml, "imports")
35
+
36
+ <<~TEMPLATE
37
+ '******* IMPORTS ******************************************************
38
+ !include #{plantuml_path}/style.uml.inc
39
+ TEMPLATE
40
+ end
41
+
42
+ def class_defs_yml_to_plantuml
43
+ return if empty?(yml, "classes") && empty?(yml, "enums")
44
+
45
+ <<~TEMPLATE
46
+ '******* CLASS DEFINITIONS ********************************************
47
+ #{join_as_plantuml(
48
+ classes_to_classes_plantuml(yml['classes']),
49
+ enums_to_enums_plantuml(yml['enums'])
50
+ )}
51
+ TEMPLATE
52
+ end
53
+
54
+ def class_groups_yml_to_plantuml
55
+ return if empty?(yml, "groups")
56
+
57
+ <<~TEMPLATE
58
+ '******* CLASS GROUPS *************************************************
59
+ #{join_as_plantuml(
60
+ groups_to_plantuml(yml['groups'])
61
+ )}
62
+ TEMPLATE
63
+ end
64
+
65
+ def class_relations_yml_to_plantuml
66
+ return if empty?(yml, "classes") && empty?(yml, "relations")
67
+
68
+ <<~TEMPLATE
69
+ '******* CLASS RELATIONS **********************************************
70
+ #{join_as_plantuml(
71
+ classes_to_relations_plantuml(yml['classes']),
72
+ relations_to_plantuml(nil, yml['relations'])
73
+ )}
74
+ TEMPLATE
75
+ end
76
+
77
+ def diagram_options_yml_to_plantuml
78
+ return if empty?(yml, "diagram_options")
79
+
80
+ <<~TEMPLATE
81
+ '******* DIAGRAM SPECIFIC CONFIG **************************************
82
+ #{join_as_plantuml(
83
+ diagram_options_to_plantuml(yml['diagram_options'])
84
+ )}
85
+ TEMPLATE
86
+ end
87
+
88
+ def bottom_yml_to_plantuml
89
+ return if empty?(yml, "bottom")
90
+
91
+ <<~TEMPLATE
92
+ '******* BOTTOM OVERRIDE CONFIG **************************************
93
+ #{join_as_plantuml(bottom_to_plantuml(yml['bottom']))}
94
+ TEMPLATE
95
+ end
96
+
97
+ def fidelity_yml_to_plantuml
98
+ return if empty?(yml, "fidelity")
99
+
100
+ <<~TEMPLATE
101
+ '******* FIDELITY *****************************************************
102
+ #{join_as_plantuml(fidelity_to_plantuml(yml['fidelity']))}
103
+ TEMPLATE
104
+ end
105
+
106
+ def classes_to_classes_plantuml(classes)
107
+ classes ||= {}
108
+
109
+ return if classes.empty?
110
+
111
+ classes.map do |(class_name, class_hash)|
112
+ class_to_plantuml(class_name, class_hash)
113
+ end.join("\n")
114
+ end
115
+
116
+ def class_to_plantuml(class_name, class_hash)
117
+ return unless class_name
118
+
119
+ class_hash ||= {}
120
+
121
+ <<~TEMPLATE
122
+ class #{class_name}#{model_stereotype_to_plantuml(class_hash['type'])} {
123
+ #{join_as_plantuml(
124
+ attributes_to_plantuml(class_hash['attributes']),
125
+ constraints_to_plantuml(class_hash['constraints'])
126
+ )}
127
+ }
128
+ TEMPLATE
129
+ end
130
+
131
+ def attributes_to_plantuml(attributes)
132
+ return unless attributes
133
+
134
+ attributes.map do |(attr_name, attr_hash)|
135
+ attribute_to_plantuml(attr_name, attr_hash)
136
+ end.join("").sub(/\n\Z/, "")
137
+ end
138
+
139
+ def attribute_to_plantuml(attr_name, attr_hash)
140
+ <<~TEMPLATE
141
+ +#{attr_name}: #{attr_hash['type']}#{attribute_cardinality_plantuml(attr_hash['cardinality'])}
142
+ TEMPLATE
143
+ end
144
+
145
+ def attribute_cardinality_plantuml(cardinality, with_bracket = true)
146
+ return "" if cardinality.nil? ||
147
+ (cardinality["min"] == cardinality["max"] &&
148
+ cardinality["min"] == 1)
149
+
150
+ card = "#{cardinality['min']}..#{cardinality['max']}"
151
+ return card unless with_bracket
152
+
153
+ "[#{card}]"
154
+ end
155
+
156
+ def constraints_to_plantuml(constraints)
157
+ constraints ||= []
158
+
159
+ return if constraints.empty?
160
+
161
+ constraints_output = constraints.map do |constraint|
162
+ " {#{constraint}}"
163
+ end
164
+
165
+ <<~TEMPLATE
166
+ __ constraints __
167
+ #{join_as_plantuml(
168
+ *constraints_output
169
+ )}
170
+ TEMPLATE
171
+ end
172
+
173
+ def classes_to_relations_plantuml(classes)
174
+ output_ary = classes.map do |(class_name, class_hash)|
175
+ class_hash ||= {}
176
+ relations = class_hash["relations"]
177
+ relations_to_plantuml(class_name, relations)
178
+ end
179
+
180
+ join_as_plantuml(*output_ary)
181
+ end
182
+
183
+ def relations_to_plantuml(class_name, relations)
184
+ return unless relations
185
+
186
+ output_ary = relations.map do |relation|
187
+ source = class_name || relation["source"]
188
+ relation_to_plantuml(source,
189
+ relation["target"],
190
+ relation)
191
+ end
192
+
193
+ join_as_plantuml(*output_ary)
194
+ end
195
+
196
+ def relation_arrow(relationship, relation)
197
+ [
198
+ relationship_type_to_plantuml("source",
199
+ relationship["source"]["type"]),
200
+ (relation["direction"]).to_s,
201
+ relationship_type_to_plantuml("target",
202
+ relationship["target"]["type"]),
203
+ ].compact.join("-")
204
+ end
205
+
206
+ def relation_label(action)
207
+ return "" unless action
208
+
209
+ case action["direction"]
210
+ when "source"
211
+ " : < #{action['verb']}"
212
+ when "target"
213
+ " : #{action['verb']} >"
214
+ else
215
+ ""
216
+ end
217
+ end
218
+
219
+ def source_arrow_end(source, relationship)
220
+ source_attribute = relationship_cardinality_to_plantuml(
221
+ relationship["source"]["attribute"]
222
+ )
223
+ [source, source_attribute].join(" ")
224
+ end
225
+
226
+ def target_arrow_end(target, relationship, action)
227
+ target_attribute = relationship_cardinality_to_plantuml(
228
+ relationship["target"]["attribute"]
229
+ )
230
+ [
231
+ [target_attribute, target].join(" "),
232
+ relation_label(action),
233
+ ].join
234
+ end
235
+
236
+ def relation_association(source, target, association)
237
+ return unless association
238
+
239
+ "\n(#{source}, #{target}) . #{association}"
240
+ end
241
+
242
+ def relation_to_plantuml(source, target, relation)
243
+ relationship = relation["relationship"] || {}
244
+ relationship["source"] ||= {}
245
+ relationship["target"] ||= {}
246
+ relation_output_lines(source, target, relation, relationship)
247
+ end
248
+
249
+ def relation_output_lines(source, target, relation, relationship)
250
+ output_lines = [
251
+ source_arrow_end(source, relationship),
252
+ relation_arrow(relationship, relation),
253
+ target_arrow_end(target, relationship, relation["action"]),
254
+ relation_association(source, target, relationship["association"]),
255
+ ].join(" ")
256
+
257
+ join_as_plantuml(*output_lines)
258
+ end
259
+
260
+ def relationship_type_to_plantuml(relation_end, relationship_type)
261
+ is_source = (relation_end == "source")
262
+ mappings = {
263
+ "direct" => is_source ? "<" : ">",
264
+ "inheritance" => is_source ? "<|" : "|>",
265
+ "composition" => "*",
266
+ "aggregation" => "o",
267
+ }
268
+ mappings.fetch(relationship_type, "")
269
+ end
270
+
271
+ def relationship_cardinality_to_plantuml(attribute)
272
+ attribute_name = (attribute || {}).keys.first
273
+
274
+ return unless attribute_name
275
+
276
+ attribute_hash = attribute[attribute_name] || {}
277
+ card = attribute_cardinality(attribute_hash["cardinality"])
278
+ "\"+#{attribute_name}#{card}\""
279
+ end
280
+
281
+ def attribute_cardinality(attribute_cardinality)
282
+ cardinality = ""
283
+ if attribute_cardinality
284
+ cardinality = attribute_cardinality_plantuml(
285
+ attribute_cardinality,
286
+ false
287
+ )
288
+ cardinality = " #{cardinality}"
289
+ end
290
+ cardinality
291
+ end
292
+
293
+ def enums_to_enums_plantuml(enums)
294
+ enums ||= {}
295
+
296
+ enums.map do |(enum_name, enum_hash)|
297
+ enum_to_plantuml(enum_name, enum_hash)
298
+ end.join("\n\n")
299
+ end
300
+
301
+ def enum_to_plantuml(enum_name, enum_hash)
302
+ enum_hash ||= {}
303
+
304
+ <<~TEMPLATE
305
+ enum #{enum_name}#{model_stereotype_to_plantuml(enum_hash['type'])} {
306
+ #{join_as_plantuml(enum_values_to_plantuml(enum_hash['values']))}
307
+ }
308
+ TEMPLATE
309
+ end
310
+
311
+ def model_stereotype_to_plantuml(model_stereotype)
312
+ return "" unless model_stereotype
313
+
314
+ " <<#{model_stereotype}>>"
315
+ end
316
+
317
+ def enum_values_to_plantuml(enum_values)
318
+ output_ary = enum_values.map do |(enum_value, _enum_value_hash)|
319
+ " #{enum_value}"
320
+ end
321
+
322
+ join_as_plantuml(*output_ary)
323
+ end
324
+
325
+ def groups_to_plantuml(groups)
326
+ groups ||= []
327
+ return if groups.empty?
328
+
329
+ groups.reduce("") do |output, group|
330
+ output += "\ntogether {\n"
331
+ group.each do |class_name|
332
+ output += "\nclass #{class_name}\n"
333
+ end
334
+ output += "\n}\n"
335
+ output
336
+ end
337
+ end
338
+
339
+ def diagram_options_to_plantuml(diagram_options)
340
+ diagram_options ||= []
341
+ return if diagram_options.empty?
342
+
343
+ "#{diagram_options.join("\n")}\n"
344
+ end
345
+
346
+ def bottom_to_plantuml(bottom)
347
+ bottom ||= []
348
+ return if bottom.empty?
349
+
350
+ "#{bottom.join("\n")}\n"
351
+ end
352
+
353
+ def format_hidden_class(accum, fidelity_classes, class_hash)
354
+ return accum if class_hash["relations"].nil?
355
+
356
+ class_hash["relations"].each_with_object(accum) do |relation, acc|
357
+ format_source_target_relation(relation, fidelity_classes, acc)
358
+ format_association_relation(relation, fidelity_classes, acc)
359
+ end
360
+ end
361
+
362
+ def format_source_target_relation(relation, fidelity_classes, acc)
363
+ %w[source target].each do |type|
364
+ next unless relation[type] && !fidelity_classes.key?(relation[type])
365
+
366
+ acc.merge!(relation[type] => true)
367
+ end
368
+ end
369
+
370
+ def format_association_relation(relation, fidelity_classes, acc)
371
+ return unless relation["relationship"] &&
372
+ relation["relationship"]["association"]
373
+
374
+ association = relation["relationship"]["association"]
375
+ return unless association && !fidelity_classes.key?(association)
376
+
377
+ acc.merge!(association => true)
378
+ end
379
+
380
+ def hide_other_classes(fidelity)
381
+ return "" if fidelity.nil? || fidelity["classes"].nil?
382
+
383
+ output = ""
384
+ hidden_classes = fidelity["classes"]
385
+ .reduce({}) do |acc, (_class_name, class_hash)|
386
+ format_hidden_class(acc, fidelity["classes"], class_hash)
387
+ end
388
+
389
+ hidden_classes.each_key do |hidden_class_name|
390
+ output += "\nhide #{hidden_class_name}\n"
391
+ end
392
+ output
393
+ end
394
+
395
+ def fidelity_to_plantuml(fidelity)
396
+ return "" if fidelity.nil?
397
+
398
+ output = ""
399
+ output += hide_other_classes(fidelity) if fidelity["hideOtherClasses"]
400
+ output += "\nhide members\n" if fidelity["hideMembers"]
401
+ output
402
+ end
403
+
404
+ def empty?(yml, prop)
405
+ yml[prop].nil? || yml[prop].length.zero?
406
+ end
407
+ end
408
+ end
409
+ end