metanorma-plugin-lutaml 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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