metanorma-standoc 1.3.29 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/lib/asciidoctor/standoc/base.rb +2 -25
- data/lib/asciidoctor/standoc/biblio.rng +13 -3
- data/lib/asciidoctor/standoc/blocks.rb +20 -17
- data/lib/asciidoctor/standoc/cleanup.rb +2 -0
- data/lib/asciidoctor/standoc/cleanup_block.rb +2 -2
- data/lib/asciidoctor/standoc/cleanup_section.rb +8 -125
- data/lib/asciidoctor/standoc/cleanup_terms.rb +134 -0
- data/lib/asciidoctor/standoc/datamodel/attributes_table_preprocessor.rb +57 -0
- data/lib/asciidoctor/standoc/datamodel/diagram_preprocessor.rb +102 -0
- data/lib/asciidoctor/standoc/datamodel/plantuml_renderer.rb +408 -0
- data/lib/asciidoctor/standoc/inline.rb +10 -5
- data/lib/asciidoctor/standoc/isodoc.rng +17 -1
- data/lib/asciidoctor/standoc/macros.rb +13 -8
- data/lib/asciidoctor/standoc/macros_yaml2text.rb +19 -13
- data/lib/asciidoctor/standoc/ref.rb +13 -56
- data/lib/asciidoctor/standoc/ref_sect.rb +124 -0
- data/lib/asciidoctor/standoc/section.rb +2 -46
- data/lib/asciidoctor/standoc/views/datamodel/model_representation.adoc.erb +30 -0
- data/lib/asciidoctor/standoc/views/datamodel/plantuml_representation.adoc.erb +20 -0
- data/lib/metanorma/standoc/version.rb +1 -1
- data/metanorma-standoc.gemspec +1 -1
- data/spec/asciidoctor-standoc/cleanup_spec.rb +51 -0
- data/spec/asciidoctor-standoc/datamodel/attributes_table_preprocessor_spec.rb +76 -0
- data/spec/asciidoctor-standoc/datamodel/diagram_preprocessor_spec.rb +72 -0
- data/spec/asciidoctor-standoc/inline_spec.rb +5 -1
- data/spec/asciidoctor-standoc/macros_spec.rb +50 -0
- data/spec/asciidoctor-standoc/macros_yaml2text_spec.rb +2 -1
- data/spec/asciidoctor-standoc/refs_spec.rb +0 -4
- data/spec/examples/datamodel/address_class_profile.adoc +4 -0
- data/spec/examples/datamodel/address_component_profile.adoc +4 -0
- data/spec/examples/datamodel/common_models_diagram.adoc +4 -0
- data/spec/examples/datamodel/models/models/AddressClassProfile.yml +90 -0
- data/spec/examples/datamodel/models/models/AddressComponentProfile.yml +63 -0
- data/spec/examples/datamodel/models/models/AddressComponentSpecification.yml +15 -0
- data/spec/examples/datamodel/models/models/AddressProfile.yml +36 -0
- data/spec/examples/datamodel/models/models/AttributeProfile.yml +32 -0
- data/spec/examples/datamodel/models/models/InterchangeAddressClassProfile.yml +79 -0
- data/spec/examples/datamodel/models/models/Localization copy.yml +23 -0
- data/spec/examples/datamodel/models/models/Localization.yml +23 -0
- data/spec/examples/datamodel/models/models/ProfileCompliantAddress.yml +36 -0
- data/spec/examples/datamodel/models/models/ProfileCompliantAddressComponent.yml +15 -0
- data/spec/examples/datamodel/models/models/Signature copy.yml +20 -0
- data/spec/examples/datamodel/models/models/Signature.yml +20 -0
- data/spec/examples/datamodel/models/models/TextDirectionCode copy.yml +16 -0
- data/spec/examples/datamodel/models/models/TextDirectionCode.yml +16 -0
- data/spec/examples/datamodel/models/models/Validity.yml +14 -0
- data/spec/examples/datamodel/models/models/iso19160-1/Address.yml +22 -0
- data/spec/examples/datamodel/models/models/iso19160-1/AddressComponent.yml +2 -0
- data/spec/examples/datamodel/models/style.uml.inc +37 -0
- data/spec/examples/datamodel/models/views/CommonModels.yml +9 -0
- data/spec/examples/datamodel/models/views/TopDown.yml +62 -0
- data/spec/examples/datamodel/top_down_diagram.adoc +4 -0
- data/spec/fixtures/macros_datamodel/address_class_profile.xml +149 -0
- data/spec/fixtures/macros_datamodel/address_component_profile.xml +71 -0
- data/spec/fixtures/macros_datamodel/common_models_diagram.xml +7 -0
- data/spec/fixtures/macros_datamodel/top_down_diagram.xml +7 -0
- data/spec/spec_helper.rb +13 -2
- data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +66 -66
- data/spec/vcr_cassettes/isobib_get_123.yml +36 -36
- data/spec/vcr_cassettes/isobib_get_123_2001.yml +16 -16
- data/spec/vcr_cassettes/isobib_get_124.yml +17 -17
- data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +8 -8
- data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +41 -38
- metadata +41 -4
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module Asciidoctor
|
6
|
+
module Standoc
|
7
|
+
module Datamodel
|
8
|
+
class AttributesTablePreprocessor < Asciidoctor::Extensions::Preprocessor
|
9
|
+
BLOCK_START_REGEXP = /\{(.+?)\.\*,(.+),(.+)\}/
|
10
|
+
BLOCK_END_REGEXP = /\A\{[A-Z]+\}\z/
|
11
|
+
MARCO_REGEXP = /\[datamodel_attributes_table,([^,]+),?(.+)?\]/
|
12
|
+
TEMPLATES_PATH = File.expand_path('../views/datamodel', __dir__).freeze
|
13
|
+
# search document for block `datamodel_attributes_table`
|
14
|
+
# read include derectives that goes after that in block and transform
|
15
|
+
# into yaml2text blocks
|
16
|
+
def process(document, reader)
|
17
|
+
input_lines = reader.readlines.to_enum
|
18
|
+
Reader.new(processed_lines(document, input_lines))
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def processed_lines(document, input_lines)
|
24
|
+
input_lines.each_with_object([]) do |line, result|
|
25
|
+
if match = line.match(MARCO_REGEXP)
|
26
|
+
yaml_path = match[1]
|
27
|
+
result.push(*parse_marco(yaml_path, document))
|
28
|
+
else
|
29
|
+
result.push(line)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse_marco(yaml_path, document)
|
35
|
+
model_representation(yaml_relative_path(yaml_path, document))
|
36
|
+
.split("\n")
|
37
|
+
end
|
38
|
+
|
39
|
+
def model_representation(model_path)
|
40
|
+
template = File.read(File.join(
|
41
|
+
TEMPLATES_PATH,
|
42
|
+
'model_representation.adoc.erb'
|
43
|
+
))
|
44
|
+
file_name = File.basename(model_path).gsub(/\.ya?ml/, '')
|
45
|
+
ERB
|
46
|
+
.new(template)
|
47
|
+
.result(binding)
|
48
|
+
end
|
49
|
+
|
50
|
+
def yaml_relative_path(file_path, document)
|
51
|
+
directory = File.dirname(document.attributes['docfile'] || '.')
|
52
|
+
document.path_resolver.system_path(file_path, directory)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
require 'asciidoctor/standoc/datamodel/plantuml_renderer'
|
5
|
+
|
6
|
+
module Asciidoctor
|
7
|
+
module Standoc
|
8
|
+
module Datamodel
|
9
|
+
class DiagramPreprocessor < Asciidoctor::Extensions::Preprocessor
|
10
|
+
BLOCK_START_REGEXP = /\{(.+?)\.\*,(.+),(.+)\}/
|
11
|
+
BLOCK_END_REGEXP = /\A\{[A-Z]+\}\z/
|
12
|
+
MARCO_REGEXP = /\[datamodel_diagram,([^,]+),?(.+)?\]/
|
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
|
+
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, 'class'))
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
def model_type(imports, type)
|
83
|
+
imports
|
84
|
+
.select do |_name, elem|
|
85
|
+
elem['modelType'] == type
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def plantuml_representations(view_hash, view_path, include_path)
|
90
|
+
yaml_directory = File.dirname(view_path)
|
91
|
+
all_imports = format_import_directives(view_hash['imports'],
|
92
|
+
include_path)
|
93
|
+
prepare_view_hash(view_hash, all_imports)
|
94
|
+
Asciidoctor::Datamodel::PlantumlRenderer
|
95
|
+
.new(view_hash, File.join(yaml_directory, '..'))
|
96
|
+
.render
|
97
|
+
.split("\n")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,408 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module Asciidoctor
|
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
|
+
card = "#{cardinality['min']}..#{cardinality['max']}"
|
150
|
+
return card unless with_bracket
|
151
|
+
|
152
|
+
"[#{card}]"
|
153
|
+
end
|
154
|
+
|
155
|
+
def constraints_to_plantuml(constraints)
|
156
|
+
constraints ||= []
|
157
|
+
|
158
|
+
return if constraints.empty?
|
159
|
+
|
160
|
+
constraints_output = constraints.map do |constraint|
|
161
|
+
" {#{constraint}}"
|
162
|
+
end
|
163
|
+
|
164
|
+
<<~TEMPLATE
|
165
|
+
__ constraints __
|
166
|
+
#{join_as_plantuml(
|
167
|
+
*constraints_output
|
168
|
+
)}
|
169
|
+
TEMPLATE
|
170
|
+
end
|
171
|
+
|
172
|
+
def classes_to_relations_plantuml(classes)
|
173
|
+
output_ary = classes.map do |(class_name, class_hash)|
|
174
|
+
class_hash ||= {}
|
175
|
+
relations = class_hash['relations']
|
176
|
+
relations_to_plantuml(class_name, relations)
|
177
|
+
end
|
178
|
+
|
179
|
+
join_as_plantuml(*output_ary)
|
180
|
+
end
|
181
|
+
|
182
|
+
def relations_to_plantuml(class_name, relations)
|
183
|
+
return unless relations
|
184
|
+
|
185
|
+
output_ary = relations.map do |relation|
|
186
|
+
source = class_name || relation['source']
|
187
|
+
relation_to_plantuml(source,
|
188
|
+
relation['target'],
|
189
|
+
relation)
|
190
|
+
end
|
191
|
+
|
192
|
+
join_as_plantuml(*output_ary)
|
193
|
+
end
|
194
|
+
|
195
|
+
def relation_arrow(relationship, relation)
|
196
|
+
[
|
197
|
+
relationship_type_to_plantuml('source',
|
198
|
+
relationship['source']['type']),
|
199
|
+
(relation['direction']).to_s,
|
200
|
+
relationship_type_to_plantuml('target',
|
201
|
+
relationship['target']['type'])
|
202
|
+
].compact.join('-')
|
203
|
+
end
|
204
|
+
|
205
|
+
def relation_label(action)
|
206
|
+
return '' unless action
|
207
|
+
|
208
|
+
case action['direction']
|
209
|
+
when 'source'
|
210
|
+
" : < #{action['verb']}"
|
211
|
+
when 'target'
|
212
|
+
" : #{action['verb']} >"
|
213
|
+
else
|
214
|
+
''
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def source_arrow_end(source, relationship)
|
219
|
+
source_attribute = relationship_cardinality_to_plantuml(
|
220
|
+
relationship['source']['attribute']
|
221
|
+
)
|
222
|
+
[source, source_attribute].join(' ')
|
223
|
+
end
|
224
|
+
|
225
|
+
def target_arrow_end(target, relationship, action)
|
226
|
+
target_attribute = relationship_cardinality_to_plantuml(
|
227
|
+
relationship['target']['attribute']
|
228
|
+
)
|
229
|
+
[
|
230
|
+
[target_attribute, target].join(' '),
|
231
|
+
relation_label(action)
|
232
|
+
].join
|
233
|
+
end
|
234
|
+
|
235
|
+
def relation_association(source, target, association)
|
236
|
+
return unless association
|
237
|
+
|
238
|
+
"\n(#{source}, #{target}) . #{association}"
|
239
|
+
end
|
240
|
+
|
241
|
+
def relation_to_plantuml(source, target, relation)
|
242
|
+
relationship = relation['relationship'] || {}
|
243
|
+
relationship['source'] ||= {}
|
244
|
+
relationship['target'] ||= {}
|
245
|
+
relation_output_lines(source, target, relation, relationship)
|
246
|
+
end
|
247
|
+
|
248
|
+
def relation_output_lines(source, target, relation, relationship)
|
249
|
+
output_lines = [
|
250
|
+
source_arrow_end(source, relationship),
|
251
|
+
relation_arrow(relationship, relation),
|
252
|
+
target_arrow_end(target, relationship, relation['action']),
|
253
|
+
relation_association(source, target, relationship['association'])
|
254
|
+
].join(' ')
|
255
|
+
|
256
|
+
join_as_plantuml(*output_lines)
|
257
|
+
end
|
258
|
+
|
259
|
+
def relationship_type_to_plantuml(relation_end, relationship_type)
|
260
|
+
is_source = (relation_end == 'source')
|
261
|
+
mappings = {
|
262
|
+
'direct' => is_source ? '<' : '>',
|
263
|
+
'inheritance' => is_source ? '<|' : '|>',
|
264
|
+
'composition' => '*',
|
265
|
+
'aggregation' => 'o'
|
266
|
+
}
|
267
|
+
mappings.fetch(relationship_type, '')
|
268
|
+
end
|
269
|
+
|
270
|
+
def relationship_cardinality_to_plantuml(attribute)
|
271
|
+
attribute_name = (attribute || {}).keys.first
|
272
|
+
|
273
|
+
return unless attribute_name
|
274
|
+
|
275
|
+
attribute_hash = attribute[attribute_name] || {}
|
276
|
+
card = attribute_cardinality(attribute_hash['cardinality'])
|
277
|
+
"\"+#{attribute_name}#{card}\""
|
278
|
+
end
|
279
|
+
|
280
|
+
def attribute_cardinality(attribute_cardinality)
|
281
|
+
cardinality = ''
|
282
|
+
if attribute_cardinality
|
283
|
+
cardinality = attribute_cardinality_plantuml(
|
284
|
+
attribute_cardinality,
|
285
|
+
false
|
286
|
+
)
|
287
|
+
cardinality = " #{cardinality}"
|
288
|
+
end
|
289
|
+
cardinality
|
290
|
+
end
|
291
|
+
|
292
|
+
def enums_to_enums_plantuml(enums)
|
293
|
+
enums ||= {}
|
294
|
+
|
295
|
+
enums.map do |(enum_name, enum_hash)|
|
296
|
+
enum_to_plantuml(enum_name, enum_hash)
|
297
|
+
end.join("\n\n")
|
298
|
+
end
|
299
|
+
|
300
|
+
def enum_to_plantuml(enum_name, enum_hash)
|
301
|
+
enum_hash ||= {}
|
302
|
+
|
303
|
+
<<~TEMPLATE
|
304
|
+
enum #{enum_name}#{model_stereotype_to_plantuml(enum_hash['type'])} {
|
305
|
+
#{join_as_plantuml(enum_values_to_plantuml(enum_hash['values']))}
|
306
|
+
}
|
307
|
+
TEMPLATE
|
308
|
+
end
|
309
|
+
|
310
|
+
def model_stereotype_to_plantuml(model_stereotype)
|
311
|
+
return '' unless model_stereotype
|
312
|
+
|
313
|
+
" <<#{model_stereotype}>>"
|
314
|
+
end
|
315
|
+
|
316
|
+
def enum_values_to_plantuml(enum_values)
|
317
|
+
output_ary = enum_values.map do |(enum_value, _enum_value_hash)|
|
318
|
+
" #{enum_value}"
|
319
|
+
end
|
320
|
+
|
321
|
+
join_as_plantuml(*output_ary)
|
322
|
+
end
|
323
|
+
|
324
|
+
def groups_to_plantuml(groups)
|
325
|
+
groups ||= []
|
326
|
+
return if groups.empty?
|
327
|
+
|
328
|
+
groups.reduce('') do |output, group|
|
329
|
+
output += "\ntogether {\n"
|
330
|
+
group.each do |class_name|
|
331
|
+
output += "\nclass #{class_name}\n"
|
332
|
+
end
|
333
|
+
output += "\n}\n"
|
334
|
+
output
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def diagram_options_to_plantuml(diagram_options)
|
339
|
+
diagram_options ||= []
|
340
|
+
return if diagram_options.empty?
|
341
|
+
|
342
|
+
"#{diagram_options.join("\n")}\n"
|
343
|
+
end
|
344
|
+
|
345
|
+
def bottom_to_plantuml(bottom)
|
346
|
+
bottom ||= []
|
347
|
+
return if bottom.empty?
|
348
|
+
|
349
|
+
"#{bottom.join("\n")}\n"
|
350
|
+
end
|
351
|
+
|
352
|
+
def format_hidden_class(accum, fidelity_classes, class_hash)
|
353
|
+
return accum if class_hash['relations'].nil?
|
354
|
+
|
355
|
+
class_hash['relations'].each_with_object(accum) do |relation, acc|
|
356
|
+
format_source_target_relation(relation, fidelity_classes, acc)
|
357
|
+
format_association_relation(relation, fidelity_classes, acc)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def format_source_target_relation(relation, fidelity_classes, acc)
|
362
|
+
%w[source target].each do |type|
|
363
|
+
next unless relation[type] && !fidelity_classes.key?(relation[type])
|
364
|
+
|
365
|
+
acc.merge!(relation[type] => true)
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
def format_association_relation(relation, fidelity_classes, acc)
|
370
|
+
return unless relation['relationship'] &&
|
371
|
+
relation['relationship']['association']
|
372
|
+
|
373
|
+
association = relation['relationship']['association']
|
374
|
+
return unless association && !fidelity_classes.key?(association)
|
375
|
+
|
376
|
+
acc.merge!(association => true)
|
377
|
+
end
|
378
|
+
|
379
|
+
def hide_other_classes(fidelity)
|
380
|
+
return '' if fidelity.nil? || fidelity['classes'].nil?
|
381
|
+
|
382
|
+
output = ''
|
383
|
+
hidden_classes = fidelity['classes']
|
384
|
+
.reduce({}) do |acc, (_class_name, class_hash)|
|
385
|
+
format_hidden_class(acc, fidelity['classes'], class_hash)
|
386
|
+
end
|
387
|
+
|
388
|
+
hidden_classes.keys.each do |hidden_class_name|
|
389
|
+
output += "\nhide #{hidden_class_name}\n"
|
390
|
+
end
|
391
|
+
output
|
392
|
+
end
|
393
|
+
|
394
|
+
def fidelity_to_plantuml(fidelity)
|
395
|
+
return '' if fidelity.nil?
|
396
|
+
|
397
|
+
output = ''
|
398
|
+
output += hide_other_classes(fidelity) if fidelity['hideOtherClasses']
|
399
|
+
output += "\nhide members\n" if fidelity['hideMembers']
|
400
|
+
output
|
401
|
+
end
|
402
|
+
|
403
|
+
def empty?(yml, prop)
|
404
|
+
yml[prop].nil? || yml[prop].length.zero?
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|