metanorma-plugin-lutaml 0.4.2 → 0.4.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfe1f241f558def33ef0fc13446d842d50aac1b1003cade580fa3b62e730b722
4
- data.tar.gz: 2d12efe1688915194f16cd857e6ca4deaf9852b98407112363bf106dcf3e60a9
3
+ metadata.gz: a594ac058de2a8fc661fa9354e32c3e53cbba9ba831eb2241866c3fe50fef39e
4
+ data.tar.gz: c9ccd2ad0f3d8bcb39da897b733f0c84a8aebf2b434f0c05e4229700e96b1042
5
5
  SHA512:
6
- metadata.gz: d6c46b1d885bc2cb06ea76c4dd5ff057e2b2944579403c8582b43e8a66fe5cb67046b49c1d00526410aba63c0f1614900d3a65e681d67e5f75a3d9b66fc18fd9
7
- data.tar.gz: 3da558c2e348387e60bdc1d0b079150c032e11dcf60731b8083b766dc129b10322c9e3f06892bfc06b8524df1ad453ed1d519153b19f55c7b34734ed20e4f614
6
+ metadata.gz: 2761bf514acf0b0861a18c7d9182834868d3061e8720373e2e57bf5f31216e7a5c66e08fee6069f93c59074c352b8f4fb6f416cbd5a1644df0d55dc6db59860e
7
+ data.tar.gz: 86489b0e1915b61997af3f55388ea4b788fe505188caca2efd40589b67c1ba4e9a0acba591d111c0af7c4943dbad1a3bd69dc0c0dd737663e93b1ada5436d046
data/README.adoc CHANGED
@@ -64,9 +64,19 @@ Where:
64
64
 
65
65
  * content within the block is called the "`template`";
66
66
 
67
- * `{example.exp}` is the location of the exp schema file that contains data to be loaded. Location of the file is computed relative to the source directory that `[lutaml]` is used (e.g., if `[lutaml,example.exp,my_context]` is invoked in an `.adoc` file located at `/foo/bar/doc.adoc`, the data file is expected to be found at `/foo/bar/example.exp`);
68
-
69
- * `{my_context}` is the name where the EXPRESS Repository read from the .exp file can be accessed with. Context object is a serialized Expressir::Model::Repository object with all variable names available. See https://github.com/lutaml/expressir[Expressir] docs for reference. `{my_context}` has `schemas` method to access Expressir https://github.com/lutaml/expressir/blob/master/lib/expressir/model/schema.rb[schemas]
67
+ * `{example.exp}` is the location of the EXPRESS schema file (`*.exp`) that
68
+ contains data to be loaded. Location of the file is computed relative to the
69
+ source directory that `[lutaml]` is used (e.g., if
70
+ `[lutaml,example.exp,my_context]` is invoked in an `.adoc` file located at
71
+ `/foo/bar/doc.adoc`, the data file is expected to be found at
72
+ `/foo/bar/example.exp`);
73
+
74
+ * `{my_context}` is the name where the EXPRESS Repository read from the .exp
75
+ file can be accessed with. Context object is a serialized
76
+ `Expressir::Model::Repository` object with all variable names available. See
77
+ https://github.com/lutaml/expressir[Expressir] docs for reference.
78
+ `{my_context}` has `schemas` method to access Expressir
79
+ https://github.com/lutaml/expressir/blob/master/lib/expressir/model/schema.rb[schemas]
70
80
 
71
81
  Will produce this output:
72
82
 
@@ -83,7 +93,11 @@ Will produce this output:
83
93
 
84
94
  This macro also supports `.lutaml` files.
85
95
 
86
- Instead of using the direct path to the file one can use `lutaml-express-index` document attribute to supply directory with express files or yaml index file to parse as well as the cache file location. The syntax is as follows:
96
+ Instead of using the direct path to the file one can use `lutaml-express-index`
97
+ document attribute to supply directory with express files or YAML index file to
98
+ parse as well as the cache file location.
99
+
100
+ The syntax is as follows:
87
101
 
88
102
  [source,adoc]
89
103
  -----
@@ -92,13 +106,15 @@ Instead of using the direct path to the file one can use `lutaml-express-index`
92
106
 
93
107
  Where:
94
108
 
95
- * `my_custom_name` - is name of the parsed express files context for the later use with lutaml macro
109
+ * `my_custom_name` - is name of the parsed EXPRESS files context for the later
110
+ use with lutaml macro
96
111
 
97
- * `dir_or_index_path` - location of directory with express files or path to yaml index file to parse
112
+ * `dir_or_index_path` - location of directory with EXPRESS files or path to the
113
+ YAML index file to parse
98
114
 
99
- * `cache_path` - optional, location of the expressir cache file to use
115
+ * `cache_path` - optional, location of the Expressir cache file to use
100
116
 
101
- Example of real usage:
117
+ Example of usage:
102
118
 
103
119
  [source,adoc]
104
120
  -----
@@ -113,9 +129,75 @@ Author
113
129
  ----
114
130
  -----
115
131
 
132
+ === Usage, `lutaml_diagram` macro
133
+
134
+ This macro allows to quickly render lutaml file as diagram image.
135
+ Given `example.lutaml` file with the content:
136
+
137
+ [source,java]
138
+ ----
139
+ diagram MyView {
140
+ title "my diagram"
141
+
142
+ enum AddressClassProfile {
143
+ imlicistAttributeProfile: CharacterString [0..1] {
144
+ definition
145
+ this is multiline with `ascidoc`
146
+ end definition
147
+ }
148
+ }
149
+
150
+ class AttributeProfile {
151
+ +addressClassProfile: CharacterString [0..1]
152
+ imlicistAttributeProfile: CharacterString [0..1] {
153
+ definition this is attribute definition
154
+ }
155
+ }
156
+ }
157
+ ----
158
+
159
+ And the `lutaml_diagram` macro:
160
+
161
+ [source,adoc]
162
+ -----
163
+ lutaml_diagram::example.lutaml[]
164
+ -----
165
+
166
+ Will add diagram image to the document
167
+
168
+ Also one can use `lutaml_diagram` block with embed lutaml code instead of block macro. Example:
169
+
170
+ [source,java]
171
+ ----
172
+ [lutaml_diagram]
173
+ ....
174
+ diagram MyView {
175
+ title "my diagram"
176
+
177
+ enum AddressClassProfile {
178
+ imlicistAttributeProfile: CharacterString [0..1] {
179
+ definition
180
+ this is multiline with `ascidoc`
181
+ end definition
182
+ }
183
+ }
184
+
185
+ class AttributeProfile {
186
+ +addressClassProfile: CharacterString [0..1]
187
+ imlicistAttributeProfile: CharacterString [0..1] {
188
+ definition this is attribute definition
189
+ }
190
+ }
191
+ }
192
+ ....
193
+ ----
194
+
195
+
116
196
  === Usage, `lutaml_uml_attributes_table` macro
117
197
 
118
- This macro allows to quickly render datamodel attributes/values tables. Given `example.lutaml` file with the content:
198
+ This macro allows to quickly render data model attributes/values tables.
199
+
200
+ Given `example.lutaml` file with the content:
119
201
 
120
202
  [source,java]
121
203
  ----
@@ -187,6 +269,193 @@ Will produce this output:
187
269
  |===
188
270
  -----
189
271
 
272
+ === Usage, `lutaml_uml_datamodel_description` macro
273
+
274
+ This macro allows to quickly render data model packages and its dependent
275
+ objects for supplied XMI file.
276
+
277
+ Given an Enterprise Architect `example.xmi` file with 2 packages:
278
+
279
+ * 'Another'
280
+ * 'CityGML'
281
+
282
+ The `lutaml_uml_datamodel_description` macro can be used:
283
+
284
+ [source,adoc]
285
+ -----
286
+ [lutaml_uml_datamodel_description, path/to/example.xmi]
287
+ --
288
+ --
289
+ [.before]
290
+ ---
291
+ my text
292
+ ---
293
+
294
+ [.before, package="Another"]
295
+ ---
296
+ text before Another package
297
+ ---
298
+
299
+ [.after, package="Another"]
300
+ ---
301
+ text after Another package
302
+ ---
303
+
304
+ [.after, package="CityGML"]
305
+ ---
306
+ text after CityGML package
307
+ ---
308
+
309
+ [.after]
310
+ ---
311
+ footer text
312
+ ---
313
+ --
314
+ --
315
+ -----
316
+
317
+ Where:
318
+
319
+ * `path/to/example.xmi` - required, path to the XMI file to render
320
+
321
+ * `[.before]` - macro to add additional text before the rendered output, can be used only once, additional occurrences of macro will overwrite text
322
+
323
+ * `[.after]` - macro to add additional text after the rendered output, can be used only once, additional occurrences of macro will overwrite text
324
+
325
+ * `[.after, package="Another"]` - macro with text to be inserted before(after in case of `.before` name) the package
326
+
327
+
328
+ Will produce this output:
329
+
330
+ [source,adoc]
331
+ -----
332
+ = preface
333
+ my text
334
+
335
+ text before Another package
336
+
337
+ === Another
338
+
339
+ [[rc_another-model_section]]
340
+ ==== Another
341
+
342
+ ==== Requirements
343
+
344
+ ==== Class Definitions
345
+
346
+ .Classes used in Another
347
+ [cols="2a,6a",options="header"]
348
+ |===
349
+ |Class |Description
350
+
351
+
352
+ |<<AbstractAtomicTimeseries-section,AbstractAtomicTimeseries>>
353
+ «»
354
+ |
355
+
356
+
357
+ |<<AbstractTimeseries-section,AbstractTimeseries>>
358
+ «»
359
+ |
360
+
361
+ ....
362
+ |===
363
+
364
+
365
+
366
+ .Data Types used in Another
367
+ [cols="2,6",options="header"]
368
+ |===
369
+ |Name |Description
370
+
371
+
372
+ |<<ADEOfAbstractAtomicTimeseries-section,ADEOfAbstractAtomicTimeseries>>
373
+ |
374
+
375
+
376
+ |<<ADEOfAbstractTimeseries-section,ADEOfAbstractTimeseries>>
377
+ |
378
+
379
+ ....
380
+ |===
381
+
382
+
383
+
384
+ .Enumerated Classes used in Another
385
+ [cols="2a,6a",options="header"]
386
+ |===
387
+ |Name |Description
388
+
389
+ |<<TimeseriesTypeValue-section,TimeseriesTypeValue>>
390
+ |
391
+
392
+ |===
393
+
394
+
395
+ ==== Additional Information
396
+
397
+ text after Another package
398
+
399
+
400
+ === CityGML
401
+
402
+ [[rc_citygml-model_section]]
403
+ ==== CityGML
404
+
405
+ ==== Requirements
406
+
407
+ ==== Class Definitions
408
+
409
+ ==== Additional Information
410
+
411
+ text after CityGML package
412
+
413
+
414
+ = footer
415
+ footer text
416
+
417
+ -----
418
+
419
+ In addition to just supplying XMI file, this macro also supports YAML
420
+ configuration file.
421
+
422
+ The format for using YAML is this:
423
+
424
+ [source,yaml]
425
+ -----
426
+ ---
427
+ packages:
428
+ # includes these packages
429
+ - "Package *"
430
+ - two*
431
+ - three
432
+ # skips these packages
433
+ - skip: four
434
+ -----
435
+
436
+ Where:
437
+
438
+ * `packages` - required, root element with the list of strings or objects
439
+
440
+ * `Package *` - pattern matching, specifies lookup condition for packages to
441
+ render.
442
+ +
443
+ NOTE: In this example, it is equal to the following regular expression: `/^Package.*$/`
444
+
445
+ * `skip: four` - object with package name to skip
446
+
447
+ Usage with macro:
448
+
449
+ [source,adoc]
450
+ -----
451
+ [lutaml_uml_datamodel_description, path/to/example.xmi, path/to/config.yml]
452
+ ....
453
+ -----
454
+
455
+ The macro processor will read supplied YAML file and arrange packages according
456
+ to the order supplied in the config file, also all packages supplied as `skip`
457
+ will be skipped during render
458
+
190
459
  == Documentation
191
460
 
192
- See https://www.metanorma.com.
461
+ Please refer to https://www.metanorma.com.
@@ -1,7 +1,9 @@
1
1
  require "metanorma/plugin/lutaml/version"
2
2
  require "metanorma/plugin/lutaml/lutaml_preprocessor"
3
3
  require "metanorma/plugin/lutaml/lutaml_uml_attributes_table_preprocessor"
4
+ require "metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor"
4
5
  require "metanorma/plugin/lutaml/lutaml_diagram_block"
6
+ require "metanorma/plugin/lutaml/lutaml_diagram_block_macro"
5
7
 
6
8
  module Metanorma
7
9
  module Plugin
@@ -0,0 +1,108 @@
1
+ {% for package in context.packages %}
2
+ {% assign before_package_key = 'before;' | append: package.name %}
3
+ {% if additional_context[before_package_key] %}
4
+ {{ additional_context[before_package_key] }}
5
+ {% endif %}
6
+ {% assign is_package_spare = package.name | slice: 0,5 %}
7
+ {% if is_package_spare == 'old: ' %}{% continue %}
8
+ {% elsif is_package_spare == 'Spare' %}{% continue %}
9
+ {% endif %}
10
+ {% assign package_name = package.name | downcase | replace: ":", "" | replace: " ", "_" %}
11
+
12
+ {% capture equalsigns %}{% for count in (1..depth) %}={% endfor %}{% endcapture %}{{equalsigns}} {{ package.name }} package
13
+ {{equalsigns}}= {{ package.name }} overview
14
+
15
+ // TODO: include blocks by base path
16
+ //{% for diagram in package.diagrams %}
17
+ //[[figure-{{ diagram.xmi_id }}]]
18
+ //.{{ diagram.name }}
19
+ //image::../../xmi-19170-only/Images/{{ diagram.xmi_id }}.png[]
20
+ //
21
+ //{% if diagram.definition %}
22
+ //{{ diagram.definition | html2adoc }}
23
+ //{% endif %}
24
+ //{% endfor %}
25
+
26
+ {% if package.packages.size > 0 %}The {{ package.name }} package is organized into
27
+ {{ package.packages.size }} packages{% assign modules_nested_size = 0 %}{% for module in package.packages %}{% assign modules_nested_size = modules_nested_size | plus: module.packages.size %}{% endfor %}{% if modules_nested_size > 0 %} with {{modules_nested_size}} modules{% endif %}:
28
+ {% endif %}
29
+ [arabic]
30
+ {% for module in package.packages %}
31
+ {% if module.packages.length > 0 %}
32
+ . {{ module.name }} package comprises:
33
+ {% for nested_module in module.packages %}
34
+ .. {{nested_module.name}} module
35
+ {% endfor %}
36
+ {% else %}
37
+ . {{ module.name }} package
38
+ {% endif %}
39
+ {% endfor %}
40
+
41
+ {% if package.classes.size > 0 %}
42
+
43
+ {{equalsigns}}= Defining tables
44
+
45
+ [arabic]
46
+ {% for klass in package.classes %}
47
+ {% assign is_klass_spare = klass.name | slice: 0,5 %}
48
+ {% if is_klass_spare == 'old: ' %}{% continue %}
49
+ {% elsif is_klass_spare == 'Spare' %}{% continue %}
50
+ {% endif %}
51
+ {% assign klass_name = klass.name | downcase | replace: ':', '' | replace: ' ', '_' %}
52
+ .<<tab-P-{{ package_name }}-C-{{ klass_name }}>> -- Elements of {{ package.name }}::{{ klass.name }}
53
+
54
+ {% endfor %}
55
+ {% for enum in package.enums %}
56
+ {% assign is_enum_spare = enum.name | slice: 0,5 %}
57
+ {% if is_enum_spare == 'old: ' %}{% continue %}
58
+ {% elsif is_enum_spare == 'Spare' %}{% continue %}
59
+ {% endif %}
60
+ {% assign enum_name = enum.name | downcase | replace: ':', '' | replace: ' ', '_' %}
61
+ .<<tab-P-{{ package_name }}-E-{{ enum_name }}>> -- Elements of {{ package.name }}::{{ enum.name }}
62
+
63
+ {% endfor %}
64
+ {% for data_type in package.data_types %}
65
+ {% assign is_data_type_spare = data_type.name | slice: 0,5 %}
66
+ {% if is_data_type_spare == 'old: ' %}{% continue %}
67
+ {% elsif is_data_type_spare == 'Spare' %}{% continue %}
68
+ {% endif %}
69
+ {% assign data_type_name = data_type.name | downcase | replace: ':', '' | replace: ' ', '_' %}
70
+ .<<tab-P-{{ package_name }}-DT-{{ data_type_name }}>> -- Elements of {{ package.name }}::{{ data_type.name }}
71
+
72
+ {% endfor %}
73
+
74
+ {% for klass in package.classes %}
75
+ {% include "packages_class" %}
76
+ {% endfor %}
77
+
78
+ {% for klass in package.enums %}
79
+ {% include "packages_enum" %}
80
+ {% endfor %}
81
+
82
+ {% for klass in package.data_types %}
83
+ {% include "packages_data_type" %}
84
+ {% endfor %}
85
+
86
+ // TODO: include blocks by base path
87
+ // {% capture requirement_filename %}requirements/REQ_{{ package_name }}{% endcapture %}
88
+ // {% capture requirement_content %}{% include requirement_filename %}{% endcapture %}
89
+ // {% unless requirement_content contains "Liquid error" %}
90
+ // The following requirements apply:
91
+ // {{ requirement_content }}
92
+ //
93
+ // {% for num in (1..5) %}
94
+ // {% capture nested_requirement_filename %}requirements/REQ_{{ package_name }}_{{num}}{% endcapture %}
95
+ // {% capture nested_requirement_content %}{% include nested_requirement_filename %}{% endcapture %}
96
+ // {% unless nested_requirement_content contains "Liquid error" %}
97
+ // {{ nested_requirement_content }}
98
+ // {% endunless %}
99
+ // {% endfor %}
100
+ // {% endunless %}
101
+
102
+ {% endif %}
103
+ {% assign after_package_key = 'after;' | append: package.name %}
104
+ {{equalsigns}}= Additional Information
105
+ {% if additional_context[after_package_key] %}
106
+ {{ additional_context[after_package_key] }}
107
+ {% endif %}
108
+ {% endfor %}
@@ -0,0 +1,81 @@
1
+ {% assign is_klass_spare = klass.name | slice: 0,5 %}
2
+ {% if is_klass_spare == 'old: ' %}{% continue %}
3
+ {% elsif is_klass_spare == 'Spare' %}{% continue %}
4
+ {% endif %}
5
+ {% assign klass_name = klass.name | downcase | replace: ':', '' | replace: ' ', '_' %}
6
+ [[tab-P-{{ package_name }}-C-{{ klass_name }}]]
7
+ .Elements of {{ package.name }}::{{ klass.name }}
8
+ [width="100%",cols="a,a,a,a,a,a,a,a"]
9
+ |===
10
+
11
+ h|Name: 7+| {{ klass.name }}
12
+
13
+ h|Definition: 7+| {{ klass.definition | html2adoc }}
14
+
15
+ h|Stereotype: 7+| {{ klass.stereotype | default: 'interface' }}
16
+
17
+ {% assign inherited = klass.associations | where: "member_end_type", "inheritance" %}
18
+ {% if inherited.size > 0 %}
19
+ h|Inheritance from: 7+| {{ inherited | map: 'member_end' | join: ", " }}
20
+ {% endif %}
21
+
22
+ {% assign generalizations = klass.associations | where: "member_end_type", "generalization" %}
23
+ {% if generalizations.size > 0 %}
24
+ h|Generalization of: 7+| {{ generalizations | map: 'member_end' | join: ", " }}
25
+ {% endif %}
26
+
27
+ h|Abstract: 7+| {{ klass.is_abstract }}
28
+ {% assign aggregations = klass.associations | where: "member_end_type", "aggregation" %}
29
+ {% if aggregations.size > 0 %}
30
+ .{{aggregations.size | plus: 1}}+h|Associations:
31
+ 4+|_Association with:_
32
+ |_Obligation_
33
+ | _Maximum occurrence_
34
+ |_Provides:_
35
+
36
+ {% for assoc in aggregations %}
37
+ 4+| {{assoc.member_end}}
38
+ | {% if assoc.member_end_cardinality %}{{ assoc.member_end_cardinality.min }}{% endif %}
39
+ | {% if assoc.member_end_cardinality %}{{ assoc.member_end_cardinality.max }}{% endif %}
40
+ | {{ assoc.member_end_attribute_name }}
41
+
42
+ {% endfor %}
43
+ {% else %}
44
+
45
+ .1+h|Associations: 7+| (none)
46
+ {% endif %}
47
+ {% if klass.attributes.size > 0 %}
48
+ .{{klass.attributes.size | plus: 1}}+h|Public attributes:
49
+ | _Name_
50
+ 2+| _Definition_
51
+ | _Derived_
52
+ | _Obligation_
53
+ | _Maximum occurrence_
54
+ | _Data type_
55
+
56
+ {% for attr in klass.attributes %}
57
+ | {{attr.name}}
58
+ 2+| {{ attr.definition | html2adoc }}
59
+ | {{ attr.is_derived }}
60
+ | {{attr.cardinality.min}}
61
+ | {{attr.cardinality.max}}
62
+ | {{attr.type}}
63
+
64
+ {% endfor %}
65
+ {% else %}
66
+ .1+h|Public attributes:
67
+ 7+| (none)
68
+ {% endif %}
69
+
70
+ {% if klass.constraints.size > 0 %}
71
+ .{{ klass.constraints.size }}+|*Constraints:*
72
+ {% for constr in klass.constraints %}
73
+ 7+| `{{ constr.body }}`
74
+
75
+ {% endfor %}
76
+ {% else %}
77
+
78
+ h|Constraints: 7+| (none)
79
+ {% endif %}
80
+
81
+ |===
@@ -0,0 +1,63 @@
1
+ {% assign is_klass_spare = klass.name | slice: 0,5 %}
2
+ {% if is_klass_spare == 'old: ' %}{% continue %}
3
+ {% elsif is_klass_spare == 'Spare' %}{% continue %}
4
+ {% endif %}
5
+ {% assign klass_name = klass.name | downcase | replace: ':', '' | replace: ' ', '_' %}
6
+ [[tab-P-{{ package_name }}-DT-{{ klass_name }}]]
7
+ .Elements of {{ package.name }}::{{ klass.name }}
8
+ [width="100%",cols="a,a,a,a,a,a,a,a"]
9
+ |===
10
+
11
+ h|Name: 7+| {{ klass.name }}
12
+
13
+ h|Definition: 7+| {{ klass.definition | html2adoc }}
14
+
15
+ h|Stereotype: 7+| {{ klass.stereotype | default: 'interface' }}
16
+
17
+ {% assign inherited = klass.associations | where: "member_end_type", "inheritance" %}
18
+ {% if inherited.size > 0 %}
19
+ h|Inheritance from: 7+| {{ inherited | map: 'member_end' | join: ", " }}
20
+ {% endif %}
21
+
22
+ {% assign generalizations = klass.associations | where: "member_end_type", "generalization" %}
23
+ {% if generalizations.size > 0 %}
24
+ h|Generalization of: 7+| {{ generalizations | map: 'member_end' | join: ", " }}
25
+ {% endif %}
26
+
27
+ h|Abstract: 7+| {{ klass.is_abstract }}
28
+ {% assign aggregations = klass.associations | where: "member_end_type", "aggregation" %}
29
+ {% if aggregations.size > 0 %}
30
+ .{{aggregations.size | plus: 1}}+h|Associations:
31
+ 4+|_Association with:_
32
+ |_Obligation_
33
+ | _Maximum occurrence_
34
+ |_Provides:_
35
+
36
+ {% for assoc in aggregations %}
37
+ 4+| {{assoc.member_end}}
38
+ | {% if assoc.member_end_cardinality %}{{ assoc.member_end_cardinality.min }}{% endif %}
39
+ | {% if assoc.member_end_cardinality %}{{ assoc.member_end_cardinality.max }}{% endif %}
40
+ | {{ assoc.member_end_attribute_name }}
41
+
42
+ {% endfor %}
43
+ {% else %}
44
+
45
+ .1+h|Associations: 7+| (none)
46
+ {% endif %}
47
+
48
+ {% if klass.attributes.size > 0 %}
49
+ .{{klass.attributes.size | plus: 1}}+h|Values:
50
+ | _Name_
51
+ 6+| _Definition_
52
+
53
+ {% for value in klass.attributes %}
54
+ | {{value.name}}
55
+ 6+| {{ value.definition | html2adoc }}
56
+
57
+ {% endfor %}
58
+ {% else %}
59
+ .1+h|Values:
60
+ 7+| (none)
61
+ {% endif %}
62
+
63
+ |===
@@ -0,0 +1,63 @@
1
+ {% assign is_klass_spare = klass.name | slice: 0,5 %}
2
+ {% if is_klass_spare == 'old: ' %}{% continue %}
3
+ {% elsif is_klass_spare == 'Spare' %}{% continue %}
4
+ {% endif %}
5
+ {% assign klass_name = klass.name | downcase | replace: ':', '' | replace: ' ', '_' %}
6
+ [[tab-P-{{ package_name }}-E-{{ klass_name }}]]
7
+ .Elements of {{ package.name }}::{{ klass.name }}
8
+ [width="100%",cols="a,a,a,a,a,a,a,a"]
9
+ |===
10
+
11
+ h|Name: 7+| {{ klass.name }}
12
+
13
+ h|Definition: 7+| {{ klass.definition | html2adoc }}
14
+
15
+ h|Stereotype: 7+| {{ klass.stereotype | default: 'interface' }}
16
+
17
+ {% assign inherited = klass.associations | where: "member_end_type", "inheritance" %}
18
+ {% if inherited.size > 0 %}
19
+ h|Inheritance from: 7+| {{ inherited | map: 'member_end' | join: ", " }}
20
+ {% endif %}
21
+
22
+ {% assign generalizations = klass.associations | where: "member_end_type", "generalization" %}
23
+ {% if generalizations.size > 0 %}
24
+ h|Generalization of: 7+| {{ generalizations | map: 'member_end' | join: ", " }}
25
+ {% endif %}
26
+
27
+ h|Abstract: 7+| {{ klass.is_abstract }}
28
+ {% assign aggregations = klass.associations | where: "member_end_type", "aggregation" %}
29
+ {% if aggregations.size > 0 %}
30
+ .{{aggregations.size | plus: 1}}+h|Associations:
31
+ 4+|_Association with:_
32
+ |_Obligation_
33
+ | _Maximum occurrence_
34
+ |_Provides:_
35
+
36
+ {% for assoc in aggregations %}
37
+ 4+| {{assoc.member_end}}
38
+ | {% if assoc.member_end_cardinality %}{{ assoc.member_end_cardinality.min }}{% endif %}
39
+ | {% if assoc.member_end_cardinality %}{{ assoc.member_end_cardinality.max }}{% endif %}
40
+ | {{ assoc.member_end_attribute_name }}
41
+
42
+ {% endfor %}
43
+ {% else %}
44
+
45
+ .1+h|Associations: 7+| (none)
46
+ {% endif %}
47
+ {% if klass.values.size > 0 %}
48
+ .{{klass.values.size | plus: 1}}+h|Values:
49
+ | _Name_
50
+ 6+| _Definition_
51
+
52
+ {% for value in klass.values %}
53
+ | {{value.name}}
54
+ 6+| {{ value.definition | html2adoc }}
55
+
56
+ {% endfor %}
57
+ {% else %}
58
+ .1+h|Values:
59
+ 7+| (none)
60
+ {% endif %}
61
+
62
+
63
+ |===
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "liquid"
4
+ require "asciidoctor"
5
+ require "asciidoctor/reader"
6
+ require "lutaml"
7
+ require "lutaml/uml"
8
+ require "metanorma/plugin/lutaml/utils"
9
+
10
+ module Metanorma
11
+ module Plugin
12
+ module Lutaml
13
+ module LutamlDiagramBase
14
+ def process(parent, reader, attrs)
15
+ uml_document = ::Lutaml::Uml::Parsers::Dsl.parse(lutaml_file(parent.document, reader))
16
+ filename = generate_file(parent, reader, uml_document)
17
+ through_attrs = generate_attrs(attrs)
18
+ through_attrs["target"] = filename
19
+ through_attrs["title"] = uml_document.caption
20
+ create_image_block(parent, through_attrs)
21
+ rescue StandardError => e
22
+ abort(parent, reader, attrs, e.message)
23
+ end
24
+
25
+ def lutaml_file(reader)
26
+ raise 'Implement me!'
27
+ end
28
+
29
+ protected
30
+
31
+ def abort(parent, reader, attrs, msg)
32
+ warn(msg)
33
+ attrs["language"] = "lutaml"
34
+ source = reader.respond_to?(:source) ? reader.source : reader
35
+ create_listing_block(
36
+ parent,
37
+ source,
38
+ attrs.reject { |k, _v| k == 1 }
39
+ )
40
+ end
41
+
42
+ # if no :imagesdir: leave image file in lutaml
43
+ def generate_file(parent, _reader, uml_document)
44
+ formatter = ::Lutaml::Uml::Formatter::Graphviz.new
45
+ formatter.type = :png
46
+
47
+ imagesdir = if parent.document.attr("imagesdir")
48
+ File.join(parent.document.attr("imagesdir"), "lutaml")
49
+ else
50
+ "lutaml"
51
+ end
52
+ result_path = Utils.relative_file_path(parent.document, imagesdir)
53
+ result_pathname = Pathname.new(result_path)
54
+ result_pathname.mkpath
55
+ File.writable?(result_pathname) || raise("Destination path #{result_path} not writable for Lutaml!")
56
+
57
+ outfile = Tempfile.new(["lutaml", ".png"])
58
+ outfile.binmode
59
+ outfile.puts(formatter.format(uml_document))
60
+
61
+ # Warning: metanorma/metanorma-standoc#187
62
+ # Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
63
+ # This is why we need to copy and then unlink.
64
+ filename = File.basename(outfile.path)
65
+ FileUtils.cp(outfile, result_pathname) && outfile.unlink
66
+
67
+ File.join(result_pathname, filename)
68
+ end
69
+
70
+ def generate_attrs(attrs)
71
+ %w(id align float title role width height alt)
72
+ .reduce({}) do |memo, key|
73
+ memo[key] = attrs[key] if attrs.has_key? key
74
+ memo
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -1,40 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "liquid"
4
- require "asciidoctor"
5
- require "asciidoctor/reader"
6
- require "lutaml"
7
- require "lutaml/uml"
8
- require "metanorma/plugin/lutaml/utils"
3
+ require "metanorma/plugin/lutaml/lutaml_diagram_base"
9
4
 
10
5
  module Metanorma
11
6
  module Plugin
12
7
  module Lutaml
13
8
  class LutamlDiagramBlock < Asciidoctor::Extensions::BlockProcessor
9
+ include LutamlDiagramBase
10
+
14
11
  use_dsl
15
12
  named :lutaml_diagram
16
13
  on_context :literal
17
14
  parse_content_as :raw
18
15
 
19
- def abort(parent, reader, attrs, msg)
20
- warn(msg)
21
- attrs["language"] = "lutaml"
22
- create_listing_block(
23
- parent,
24
- reader.source,
25
- attrs.reject { |k, _v| k == 1 }
26
- )
27
- end
16
+ def lutaml_file(document, reader)
28
17
 
29
- def process(parent, reader, attrs)
30
- uml_document = ::Lutaml::Uml::Parsers::Dsl.parse(lutaml_temp(parent.document, reader))
31
- filename = generate_file(parent, reader, uml_document)
32
- through_attrs = generate_attrs(attrs)
33
- through_attrs["target"] = filename
34
- through_attrs["title"] = uml_document.caption
35
- create_image_block(parent, through_attrs)
36
- rescue StandardError => e
37
- abort(parent, reader, attrs, e.message)
18
+ lutaml_temp(document, reader)
38
19
  end
39
20
 
40
21
  private
@@ -45,42 +26,6 @@ module Metanorma
45
26
  temp_file.rewind
46
27
  temp_file
47
28
  end
48
-
49
- # if no :imagesdir: leave image file in lutaml
50
- def generate_file(parent, _reader, uml_document)
51
- formatter = ::Lutaml::Uml::Formatter::Graphviz.new
52
- formatter.type = :png
53
-
54
- imagesdir = if parent.document.attr("imagesdir")
55
- File.join(parent.document.attr("imagesdir"), "lutaml")
56
- else
57
- "lutaml"
58
- end
59
- result_path = Utils.relative_file_path(parent.document, imagesdir)
60
- result_pathname = Pathname.new(result_path)
61
- result_pathname.mkpath
62
- File.writable?(result_pathname) || raise("Destination path #{result_path} not writable for Lutaml!")
63
-
64
- outfile = Tempfile.new(["lutaml", ".png"])
65
- outfile.binmode
66
- outfile.puts(formatter.format(uml_document))
67
-
68
- # Warning: metanorma/metanorma-standoc#187
69
- # Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
70
- # This is why we need to copy and then unlink.
71
- filename = File.basename(outfile.path)
72
- FileUtils.cp(outfile, result_pathname) && outfile.unlink
73
-
74
- File.join(result_pathname, filename)
75
- end
76
-
77
- def generate_attrs(attrs)
78
- %w(id align float title role width height alt)
79
- .reduce({}) do |memo, key|
80
- memo[key] = attrs[key] if attrs.has_key? key
81
- memo
82
- end
83
- end
84
29
  end
85
30
  end
86
31
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "metanorma/plugin/lutaml/lutaml_diagram_base"
4
+
5
+ module Metanorma
6
+ module Plugin
7
+ module Lutaml
8
+ class LutamlDiagramBlockMacro < Asciidoctor::Extensions::BlockMacroProcessor
9
+ include LutamlDiagramBase
10
+
11
+ use_dsl
12
+ named :lutaml_diagram
13
+
14
+ def lutaml_file(document, file_path)
15
+ File.new(Utils.relative_file_path(document, file_path))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -89,7 +89,7 @@ module Metanorma
89
89
  |Name |Definition |Mandatory/ Optional/ Conditional |Max Occur |Data Type
90
90
 
91
91
  {% for item in definition.attributes %}
92
- |{{ item.name }} |{% if item.definition %}{{ item.definition }}{% else %}TODO: enum {{ key }}'s definition{% endif %} |{% if item.cardinality.min == "0" %}O{% else %}M{% endif %} |{% if item.cardinality.max == "*" %}N{% else %}1{% endif %} |{% if item.origin %}<<{{ item.origin }}>>{% endif %} `{{ item.type }}`
92
+ |{{ item.name }} |{% if item.definition %}{{ item.definition }}{% endif %} |{% if item.cardinality.min == "0" %}O{% else %}M{% endif %} |{% if item.cardinality.max == "*" %}N{% else %}1{% endif %} |{% if item.origin %}<<{{ item.origin }}>>{% endif %} `{{ item.type }}`
93
93
  {% endfor %}
94
94
  |===
95
95
  {% endif %}
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "liquid"
4
+ require "asciidoctor"
5
+ require "asciidoctor/reader"
6
+ require "lutaml"
7
+ require "lutaml/uml"
8
+ require "metanorma/plugin/lutaml/utils"
9
+
10
+ module Metanorma
11
+ module Plugin
12
+ module Lutaml
13
+ # Macro for quick rendering of datamodel attributes/values table
14
+ # @example [lutaml_uml_attributes_table,path/to/lutaml,EntityName]
15
+ class LutamlUmlDatamodelDescriptionPreprocessor <
16
+ Asciidoctor::Extensions::Preprocessor
17
+ MARCO_REGEXP =
18
+ /\[lutaml_uml_datamodel_description,([^,]+),?(.+)?\]/
19
+ SUPPORTED_NESTED_MACROSES = %w[before after].freeze
20
+ LIQUID_INCLUDE_PATH = File.join(
21
+ Gem.loaded_specs["metanorma-plugin-lutaml"].full_gem_path,
22
+ "lib", "metanorma", "plugin", "lutaml", "liquid_templates"
23
+ )
24
+ # search document for block `lutaml_uml_datamodel_description`
25
+ # read include derectives that goes after that in block and transform
26
+ # into yaml2text blocks
27
+ def process(document, reader)
28
+ input_lines = reader.readlines.to_enum
29
+ Asciidoctor::Reader.new(processed_lines(document, input_lines))
30
+ end
31
+
32
+ private
33
+
34
+ def lutaml_document_from_file(document, file_path)
35
+ ::Lutaml::Parser
36
+ .parse(File.new(Utils.relative_file_path(document, file_path),
37
+ encoding: "UTF-8"))
38
+ .first
39
+ end
40
+
41
+ def parse_yaml_config_file(document, file_path)
42
+ return {} if file_path.nil?
43
+
44
+ relative_file_path = Utils.relative_file_path(document, file_path)
45
+ YAML.load(File.read(relative_file_path, encoding: "UTF-8"))
46
+ end
47
+
48
+ def processed_lines(document, input_lines)
49
+ result = []
50
+ loop do
51
+ result.push(*process_text_blocks(document, input_lines))
52
+ end
53
+ result
54
+ end
55
+
56
+ def process_text_blocks(document, input_lines)
57
+ line = input_lines.next
58
+ block_match = line.match(MARCO_REGEXP)
59
+ return [line] if block_match.nil?
60
+
61
+ model_representation(
62
+ lutaml_document_from_file(document, block_match[1]),
63
+ document,
64
+ collect_additional_context(input_lines, input_lines.next),
65
+ parse_yaml_config_file(document, block_match[2]))
66
+ end
67
+
68
+ def collect_additional_context(input_lines, end_mark)
69
+ additional_context = {}
70
+ while (block_line = input_lines.next) != end_mark
71
+ nested_match = SUPPORTED_NESTED_MACROSES
72
+ .map { |macro| [macro, block_line.match(/\[.#{macro}(,\s*package=("|')(?<package>.+?)("|'))?\]/)] }
73
+ .detect { |n| !n.last.nil? }
74
+ nested_context_value = []
75
+ if nested_match
76
+ macro_keyword = [nested_match.first, nested_match.last['package']].compact.join(";")
77
+ nested_end_mark = input_lines.next
78
+ while (block_line = input_lines.next) != nested_end_mark
79
+ nested_context_value.push(block_line)
80
+ end
81
+ additional_context[macro_keyword] = nested_context_value
82
+ .join("\n")
83
+ end
84
+ end
85
+ additional_context
86
+ end
87
+
88
+ def create_context_object(lutaml_document, additional_context, options)
89
+ root_package = lutaml_document.to_liquid['packages'].first
90
+ all_packages = [root_package, *root_package['children_packages']]
91
+ {
92
+ "packages" => sort_and_filter_out_packages(all_packages, options),
93
+ "additional_context" => additional_context
94
+ }
95
+ end
96
+
97
+ def sort_and_filter_out_packages(all_packages, options)
98
+ return all_packages if options['packages'].nil?
99
+
100
+ result = []
101
+ # Step one - filter out all skipped packages
102
+ options['packages']
103
+ .find_all { |entity| entity.is_a?(Hash) && entity['skip'] }
104
+ .each do |entity|
105
+ entity_regexp = config_entity_regexp(entity['skip'])
106
+ all_packages
107
+ .delete_if {|package| package['name'] =~ entity_regexp }
108
+ end
109
+ # Step two - select supplied packages by pattern
110
+ options['packages']
111
+ .find_all { |entity| entity.is_a?(String) }
112
+ .each do |entity|
113
+ entity_regexp = config_entity_regexp(entity)
114
+ all_packages.each.with_index do |package|
115
+ if package['name'] =~ entity_regexp
116
+ result.push(package)
117
+ all_packages
118
+ .delete_if {|nest_package| nest_package['name'] == package['name'] }
119
+ end
120
+ end
121
+ end
122
+ result
123
+ end
124
+
125
+ def config_entity_regexp(entity)
126
+ additional_sym = '.*' if entity =~ /\*$/
127
+ %r{^#{Regexp.escape(entity.gsub('*', ''))}#{additional_sym}$}
128
+ end
129
+
130
+ def model_representation(lutaml_document, document, additional_context, options)
131
+ render_result, errors = Utils.render_liquid_string(
132
+ template_string: table_template,
133
+ context_items: create_context_object(lutaml_document,
134
+ additional_context,
135
+ options),
136
+ context_name: "context",
137
+ document: document,
138
+ include_path: LIQUID_INCLUDE_PATH
139
+ )
140
+ Utils.notify_render_errors(document, errors)
141
+ render_result.split("\n")
142
+ end
143
+
144
+ def table_template
145
+ <<~LIQUID
146
+ {% include "packages", depth: 2, context: context, additional_context: context.additional_context %}
147
+ LIQUID
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -22,10 +22,11 @@ module Metanorma
22
22
  end
23
23
 
24
24
  def render_liquid_string(template_string:, context_items:,
25
- context_name:, document:)
25
+ context_name:, document:, include_path: nil)
26
26
  liquid_template = ::Liquid::Template.parse(template_string)
27
27
  # Allow includes for the template
28
- liquid_template.registers[:file_system] = ::Liquid::LocalFileSystem.new(Utils.relative_file_path(document, ""))
28
+ include_path ||= Utils.relative_file_path(document, "")
29
+ liquid_template.registers[:file_system] = ::Liquid::LocalFileSystem.new(include_path)
29
30
  rendered_string = liquid_template
30
31
  .render(context_name => context_items,
31
32
  strict_variables: true,
@@ -1,7 +1,7 @@
1
1
  module Metanorma
2
2
  module Plugin
3
3
  module Lutaml
4
- VERSION = "0.4.2".freeze
4
+ VERSION = "0.4.3".freeze
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma-plugin-lutaml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-16 00:00:00.000000000 Z
11
+ date: 2021-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -257,9 +257,16 @@ files:
257
257
  - lib/metanorma-plugin-lutaml.rb
258
258
  - lib/metanorma/plugin/lutaml/express_remarks_decorator.rb
259
259
  - lib/metanorma/plugin/lutaml/liquid/custom_filters.rb
260
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages.liquid
261
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_class.liquid
262
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_data_type.liquid
263
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_enum.liquid
264
+ - lib/metanorma/plugin/lutaml/lutaml_diagram_base.rb
260
265
  - lib/metanorma/plugin/lutaml/lutaml_diagram_block.rb
266
+ - lib/metanorma/plugin/lutaml/lutaml_diagram_block_macro.rb
261
267
  - lib/metanorma/plugin/lutaml/lutaml_preprocessor.rb
262
268
  - lib/metanorma/plugin/lutaml/lutaml_uml_attributes_table_preprocessor.rb
269
+ - lib/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor.rb
263
270
  - lib/metanorma/plugin/lutaml/utils.rb
264
271
  - lib/metanorma/plugin/lutaml/version.rb
265
272
  - metanorma-plugin-lutaml.gemspec