metanorma-plugin-lutaml 0.4.1 → 0.4.5

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: d99e7b02bf3bfbddcf2d2f81d47e0a83e33abdc0617a9032a106e6930cb05f30
4
- data.tar.gz: bfc083ccb6fbd3e7824805e90515340812a1a44ba9522485d5b7a9969c36de2a
3
+ metadata.gz: 0a510a5a23684dee91557fb6047267ca6ac87be25cbe11e0bcad8e4c0d0812b9
4
+ data.tar.gz: 5d6e5cfc99c66b42ed50b7f6c6b1346fd2887ee9bba4436cacd5fbc56121dde6
5
5
  SHA512:
6
- metadata.gz: 4f4f9659c0cc4b62cfdd16e43d771eda047ff29c9731d9b397d186a6f0d214681c9c05f7a09f5ccfc70382fcfafae7df0ff833966d8454be2f947ca3ced9e376
7
- data.tar.gz: dc4de40cee4c6ea453936fe4097f732bea18aa5c92ecedbf9789a9719a994edb4afd0088d9b13fffdfc811b960be391c4272282cb39c063685c46e8865fad2b6
6
+ metadata.gz: ea2e863ee349fb9bc5e60c43802569b0592b3437f2aad58f5bdb5591ecd430388566aff7ad8ff6d6c187e64868df9f1f303917afa94e73396e5c6d6564d0571a
7
+ data.tar.gz: dc8d9a72fbea070f7aec02fa576c59859ce34abf6375e307ef18685cdbd70130edcc3958839e7b82e9e7155befc8b51657c685d5f42cef96e900de0fd4a50532
@@ -4,7 +4,7 @@ name: rake
4
4
 
5
5
  on:
6
6
  push:
7
- branches: [ master, main ]
7
+ branches: [ master, main ]
8
8
  tags: [ v* ]
9
9
  pull_request:
10
10
 
@@ -16,19 +16,9 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- ruby: [ '2.7', '2.6', '2.5', '2.4' ]
19
+ ruby: [ '3.0', '2.7', '2.6', '2.5' ]
20
20
  os: [ ubuntu-latest, windows-latest, macos-latest ]
21
21
  experimental: [ false ]
22
- include:
23
- - ruby: '3.0'
24
- os: 'ubuntu-latest'
25
- experimental: true
26
- - ruby: '3.0'
27
- os: 'windows-latest'
28
- experimental: true
29
- - ruby: '3.0'
30
- os: 'macos-latest'
31
- experimental: true
32
22
  steps:
33
23
  - uses: actions/checkout@master
34
24
 
@@ -49,5 +39,5 @@ jobs:
49
39
  with:
50
40
  token: ${{ secrets.METANORMA_CI_PAT_TOKEN || secrets.GITHUB_TOKEN }}
51
41
  repository: ${{ github.repository }}
52
- event-type: notify
42
+ event-type: tests-passed
53
43
  client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
data/.hound.yml ADDED
@@ -0,0 +1,5 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
+ ruby:
4
+ enabled: true
5
+ config_file: .rubocop.yml
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
+ inherit_from:
4
+ - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
5
+
6
+ # local repo-specific modifications
7
+ # ...
8
+
9
+ AllCops:
10
+ TargetRubyVersion: 2.5
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,215 @@ 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
+ [.before]
289
+ ...
290
+ my text
291
+ ...
292
+
293
+ [.diagram_include_block, base_path="requirements/"]
294
+ ...
295
+ Diagram text
296
+ ...
297
+
298
+ [.include_block, package="Another", base_path="spec/fixtures"]
299
+ ...
300
+ my text
301
+ ...
302
+
303
+ [.include_block, base_path="spec/fixtures"]
304
+ ...
305
+ my text
306
+ ...
307
+
308
+ [.before, package="Another"]
309
+ ...
310
+ text before Another package
311
+ ...
312
+
313
+ [.after, package="Another"]
314
+ ...
315
+ text after Another package
316
+ ...
317
+
318
+ [.after, package="CityGML"]
319
+ ...
320
+ text after CityGML package
321
+ ...
322
+
323
+ [.after]
324
+ ...
325
+ footer text
326
+ ...
327
+ --
328
+ --
329
+ -----
330
+
331
+ Where:
332
+
333
+ * `path/to/example.xmi` - required, path to the XMI file to render
334
+
335
+ * `[.before]` - macro to add additional text before the rendered output, can be used only once, additional occurrences of macro will overwrite text
336
+
337
+ * `[.after]` - macro to add additional text after the rendered output, can be used only once, additional occurrences of macro will overwrite text
338
+
339
+ * `[.after, package="Another"]` - macro with text to be inserted before(after in case of `.before` name) the package
340
+
341
+ * `[.diagram_include_block]` - macro to automatically include diagram images. Attribute `base_path` is a required attribute to supply path prefix where to look for a digram image. The logic is as follows:
342
+ [source,adoc]
343
+ -----
344
+ {% for diagram in package.diagrams %}
345
+ [[figure-{{ diagram.xmi_id }}]]
346
+ .{{ diagram.name }}
347
+ image::{{ image_base_path }}/{{ diagram.xmi_id }}.png[]
348
+
349
+ {% if diagram.definition %}
350
+ {{ diagram.definition | html2adoc }}
351
+ {% endif %}
352
+ {% endfor %}
353
+ -----
354
+ Eg: script will take package diagrams supplied in xmi file and will try to include `image` with the name equal to diagram' xmi_id attribute plus `.png`. Also one can add any text to the macro text, it will be added as paragraph before each image include.
355
+
356
+ * `[.diagram_include_block, package="Another"]` - same as above, but diagram will be included only for supplied package name
357
+
358
+ * `[.include_block, base_path="spec/fixtures"]` - macro to inlude files(adoc/liquid) for each package name. Attribute `base_path` is a required attribute to supply path prefix where to look for file to include. Macro will look for a file called `base_path` + `/` `_package_name`(downcase, replace : -> '', ' ' -> '_') + `.adoc`[`.liquid`], eg for package 'My Package name' and `base_path` eq to `my/path`, macro will look for the following file path: `my/path/_my_package_name.adoc`.
359
+
360
+ * `[.include_block, package="Another", base_path="spec/fixtures"]` - same as above, but include block will be included only for supplied package name
361
+
362
+
363
+ Will produce this output:
364
+
365
+ [source,adoc]
366
+ -----
367
+ my text
368
+ == CityGML package
369
+ === CityGML overview
370
+
371
+ Diagram text
372
+
373
+ [[figure-EAID_ACBB5EE3_3428_40f5_9C7C_E41923419F29]]
374
+ .CityGML Package Diagram
375
+ image::requirements//EAID_ACBB5EE3_3428_40f5_9C7C_E41923419F29.png[]
376
+
377
+ BuildingFurnitureFunctionValue is a code list that enumerates the different purposes of a BuildingFurniture.
378
+
379
+ [[figure-EAID_938AE961_1C57_4052_B964_997D1894A58D]]
380
+ .Use of ISO and OASIS standards in CityGML
381
+ image::requirements//EAID_938AE961_1C57_4052_B964_997D1894A58D.png[]
382
+
383
+ The CityGML package is organized into
384
+ 2 packages with 1 modules:
385
+
386
+ [arabic]
387
+ . Another package
388
+ . CityTML package
389
+
390
+ my text
391
+
392
+ Content for CityGML package
393
+
394
+ ==== Defining tables
395
+
396
+ [arabic]
397
+ .<<tab-P-another-C-abstractatomictimeseries>> -- Elements of Another::AbstractAtomicTimeseries
398
+
399
+ [[tab-P-another-C-abstractatomictimeseries]]
400
+ .Elements of Another::AbstractAtomicTimeseries
401
+ [width="100%",cols="a,a,a,a,a,a,a,a"]
402
+ |===
403
+ h|Name: 7+| AbstractAtomicTimeseries
404
+ h|Definition: 7+|
405
+ h|Stereotype: 7+| interface
406
+ h|Abstract: 7+|
407
+ .1+h|Associations: 7+| (none)
408
+ .4+h|Public attributes:
409
+ | _Name_
410
+ 2+| _Definition_
411
+ | _Derived_
412
+ | _Obligation_
413
+ | _Maximum occurrence_
414
+ | _Data type_
415
+ | adeOfAbstractAtomicTimeseries
416
+ 2+|
417
+ |
418
+ | C
419
+ | *
420
+ | ADEOfAbstractAtomicTimeseries
421
+ | observationProperty
422
+ 2+|
423
+ |
424
+ | M
425
+ | 1
426
+ | CharacterString
427
+ | uom
428
+ 2+|
429
+ |
430
+ | C
431
+ | 1
432
+ | CharacterString
433
+ h|Constraints: 7+| (none)
434
+ |===
435
+
436
+ === Additional Information
437
+
438
+ text after CityGML package
439
+ -----
440
+
441
+ In addition to just supplying XMI file, this macro also supports YAML
442
+ configuration file.
443
+
444
+ The format for using YAML is this:
445
+
446
+ [source,yaml]
447
+ -----
448
+ ---
449
+ packages:
450
+ # includes these packages
451
+ - "Package *"
452
+ - two*
453
+ - three
454
+ # skips these packages
455
+ - skip: four
456
+ -----
457
+
458
+ Where:
459
+
460
+ * `packages` - required, root element with the list of strings or objects
461
+
462
+ * `Package *` - pattern matching, specifies lookup condition for packages to
463
+ render.
464
+ +
465
+ NOTE: In this example, it is equal to the following regular expression: `/^Package.*$/`
466
+
467
+ * `skip: four` - object with package name to skip
468
+
469
+ Usage with macro:
470
+
471
+ [source,adoc]
472
+ -----
473
+ [lutaml_uml_datamodel_description, path/to/example.xmi, path/to/config.yml]
474
+ ....
475
+ -----
476
+
477
+ The macro processor will read supplied YAML file and arrange packages according
478
+ to the order supplied in the config file, also all packages supplied as `skip`
479
+ will be skipped during render
480
+
190
481
  == Documentation
191
482
 
192
- See https://www.metanorma.com.
483
+ 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,53 @@
1
+ module Metanorma
2
+ module Plugin
3
+ module Lutaml
4
+ module Liquid
5
+ class LocalFileSystem
6
+ attr_accessor :roots, :patterns
7
+
8
+ def initialize(roots, patterns = ["_%s.liquid"])
9
+ @roots = roots
10
+ @patterns = patterns
11
+ end
12
+
13
+ def read_template_file(template_path)
14
+ full_path = full_path(template_path)
15
+ raise FileSystemError, "No such template '#{template_path}'" unless File.exist?(full_path)
16
+
17
+ File.read(full_path)
18
+ end
19
+
20
+ def full_path(template_path)
21
+ raise ::Liquid::FileSystemError, "Illegal template name '#{template_path}'" unless %r{\A[^./][a-zA-Z0-9_/]+\z}.match?(template_path)
22
+
23
+ result_path = if template_path.include?('/')
24
+ roots
25
+ .map do |root|
26
+ patterns.map do |pattern|
27
+ File.join(root, File.dirname(template_path), pattern % File.basename(template_path))
28
+ end
29
+ end
30
+ .flatten
31
+ .find { |path| File.file?(path) }
32
+ else
33
+ roots
34
+ .map do |root|
35
+ patterns.map do |pattern|
36
+ File.join(root, pattern % template_path)
37
+ end
38
+ end
39
+ .flatten
40
+ .find { |path| File.file?(path) }
41
+ end
42
+
43
+ unless roots.any? { |root| File.expand_path(result_path).start_with?(File.expand_path(root)) }
44
+ raise ::Liquid::FileSystemError, "Illegal template path '#{File.expand_path(result_path)}'"
45
+ end
46
+
47
+ result_path
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,11 @@
1
+ {{ text }}
2
+
3
+ {% for diagram in package.diagrams %}
4
+ [[figure-{{ diagram.xmi_id }}]]
5
+ .{{ diagram.name }}
6
+ image::{{ image_base_path }}/{{ diagram.xmi_id }}.png[]
7
+
8
+ {% if diagram.definition %}
9
+ {{ diagram.definition | html2adoc }}
10
+ {% endif %}
11
+ {% endfor %}
@@ -0,0 +1,119 @@
1
+ {% for package in context.packages %}
2
+ {% assign package_name = package.name | downcase | replace: ":", "" | replace: " ", "_" %}
3
+ {% if additional_context.before %}
4
+ {{ additional_context.before.text }}
5
+ {% endif %}
6
+ {% assign before_package_key = 'before;' | append: package.name %}
7
+ {% if additional_context[before_package_key] %}
8
+ {{ additional_context[before_package_key].text }}
9
+ {% endif %}
10
+ {% assign is_package_spare = package.name | slice: 0,5 %}
11
+ {% if is_package_spare == 'old: ' %}{% continue %}
12
+ {% elsif is_package_spare == 'Spare' %}{% continue %}
13
+ {% endif %}
14
+
15
+ {% capture equalsigns %}{% for count in (1..depth) %}={% endfor %}{% endcapture %}{{equalsigns}} {{ package.name }} package
16
+ {{equalsigns}}= {{ package.name }} overview
17
+
18
+ {% if additional_context.diagram_include_block %}
19
+ {% include "diagrams_block", package_name: package_name, image_base_path: additional_context.diagram_include_block.base_path, text: additional_context.diagram_include_block.text %}
20
+ {% endif %}
21
+
22
+ {% if package.packages.size > 0 %}The {{ package.name }} package is organized into
23
+ {{ 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 %}:
24
+ {% endif %}
25
+ [arabic]
26
+ {% for module in package.packages %}
27
+ {% if module.packages.length > 0 %}
28
+ . {{ module.name }} package comprises:
29
+ {% for nested_module in module.packages %}
30
+ .. {{nested_module.name}} module
31
+ {% endfor %}
32
+ {% else %}
33
+ . {{ module.name }} package
34
+ {% endif %}
35
+ {% endfor %}
36
+
37
+ {% if package.classes.size > 0 or package.enums.size > 0 or package.data_types.size > 0 %}
38
+
39
+ {{equalsigns}}= Defining tables
40
+
41
+ [arabic]
42
+ {% for klass in package.classes %}
43
+ {% assign is_klass_spare = klass.name | slice: 0,5 %}
44
+ {% if is_klass_spare == 'old: ' %}{% continue %}
45
+ {% elsif is_klass_spare == 'Spare' %}{% continue %}
46
+ {% endif %}
47
+ {% assign klass_name = klass.name | downcase | replace: ':', '' | replace: ' ', '_' %}
48
+ .<<tab-P-{{ package_name }}-C-{{ klass_name }}>> -- Elements of {{ package.name }}::{{ klass.name }}
49
+
50
+ {% endfor %}
51
+ {% for enum in package.enums %}
52
+ {% assign is_enum_spare = enum.name | slice: 0,5 %}
53
+ {% if is_enum_spare == 'old: ' %}{% continue %}
54
+ {% elsif is_enum_spare == 'Spare' %}{% continue %}
55
+ {% endif %}
56
+ {% assign enum_name = enum.name | downcase | replace: ':', '' | replace: ' ', '_' %}
57
+ .<<tab-P-{{ package_name }}-E-{{ enum_name }}>> -- Elements of {{ package.name }}::{{ enum.name }}
58
+
59
+ {% endfor %}
60
+ {% for data_type in package.data_types %}
61
+ {% assign is_data_type_spare = data_type.name | slice: 0,5 %}
62
+ {% if is_data_type_spare == 'old: ' %}{% continue %}
63
+ {% elsif is_data_type_spare == 'Spare' %}{% continue %}
64
+ {% endif %}
65
+ {% assign data_type_name = data_type.name | downcase | replace: ':', '' | replace: ' ', '_' %}
66
+ .<<tab-P-{{ package_name }}-DT-{{ data_type_name }}>> -- Elements of {{ package.name }}::{{ data_type.name }}
67
+
68
+ {% endfor %}
69
+
70
+ {% for klass in package.classes %}
71
+ {% include "packages_class" %}
72
+ {% endfor %}
73
+
74
+ {% for klass in package.enums %}
75
+ {% include "packages_enum" %}
76
+ {% endfor %}
77
+
78
+ {% for klass in package.data_types %}
79
+ {% include "packages_data_type" %}
80
+ {% endfor %}
81
+
82
+ {% endif %}
83
+
84
+ {% if additional_context.include_block %}
85
+ {% assign block = additional_context.include_block %}
86
+ {% capture block_filename %}{{ block.base_path }}/{{ package_name }}{% endcapture %}
87
+ {% capture block_content %}{% include block_filename %}{% endcapture %}
88
+ {% unless block_content contains "Liquid error" %}
89
+ {% if block.text %}
90
+ {{ block.text }}
91
+ {% endif %}
92
+ {{ block_content }}
93
+ {% endunless %}
94
+ {% endif %}
95
+
96
+ {% assign include_block_package_key = 'include_block;' | append: package.name %}
97
+ {% assign block = additional_context[include_block_package_key] %}
98
+ {% if block %}
99
+ {% capture block_filename %}{{ block.base_path }}/{{ package_name }}{% endcapture %}
100
+ {% capture block_content %}{% include block_filename %}{% endcapture %}
101
+ {% unless block_content contains "Liquid error" %}
102
+ {% if block.text %}
103
+ {{ block.text }}
104
+ {% endif %}
105
+ {{ block_content }}
106
+ {% endunless %}
107
+ {% endif %}
108
+
109
+ {% assign after_package_key = 'after;' | append: package.name %}
110
+ {{equalsigns}}= Additional Information
111
+ {% if additional_context[after_package_key] %}
112
+ {{ additional_context[after_package_key].text }}
113
+ {% endif %}
114
+ {% if package.packages.size > 0 and render_nested_packages %}{% assign nested_depth = depth | plus: 1 %}{% include "packages", depth: nested_depth, context: package %}{% endif %}
115
+ {% endfor %}
116
+
117
+ {% if additional_context.after %}
118
+ {{ additional_context.after.text }}
119
+ {% endif %}
@@ -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,81 @@
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 "lutaml/formatter"
9
+ require "metanorma/plugin/lutaml/utils"
10
+
11
+ module Metanorma
12
+ module Plugin
13
+ module Lutaml
14
+ module LutamlDiagramBase
15
+ def process(parent, reader, attrs)
16
+ uml_document = ::Lutaml::Uml::Parsers::Dsl.parse(lutaml_file(parent.document, reader))
17
+ filename = generate_file(parent, reader, uml_document)
18
+ through_attrs = generate_attrs(attrs)
19
+ through_attrs["target"] = filename
20
+ through_attrs["title"] = uml_document.caption
21
+ create_image_block(parent, through_attrs)
22
+ rescue StandardError => e
23
+ abort(parent, reader, attrs, e.message)
24
+ end
25
+
26
+ def lutaml_file(reader)
27
+ raise 'Implement me!'
28
+ end
29
+
30
+ protected
31
+
32
+ def abort(parent, reader, attrs, msg)
33
+ warn(msg)
34
+ attrs["language"] = "lutaml"
35
+ source = reader.respond_to?(:source) ? reader.source : reader
36
+ create_listing_block(
37
+ parent,
38
+ source,
39
+ attrs.reject { |k, _v| k == 1 }
40
+ )
41
+ end
42
+
43
+ # if no :imagesdir: leave image file in lutaml
44
+ def generate_file(parent, _reader, uml_document)
45
+ formatter = ::Lutaml::Formatter::Graphviz.new
46
+ formatter.type = :png
47
+
48
+ imagesdir = if parent.document.attr("imagesdir")
49
+ File.join(parent.document.attr("imagesdir"), "lutaml")
50
+ else
51
+ "lutaml"
52
+ end
53
+ result_path = Utils.relative_file_path(parent.document, imagesdir)
54
+ result_pathname = Pathname.new(result_path)
55
+ result_pathname.mkpath
56
+ File.writable?(result_pathname) || raise("Destination path #{result_path} not writable for Lutaml!")
57
+
58
+ outfile = Tempfile.new(["lutaml", ".png"])
59
+ outfile.binmode
60
+ outfile.puts(formatter.format(uml_document))
61
+
62
+ # Warning: metanorma/metanorma-standoc#187
63
+ # Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
64
+ # This is why we need to copy and then unlink.
65
+ filename = File.basename(outfile.path)
66
+ FileUtils.cp(outfile, result_pathname) && outfile.unlink
67
+
68
+ File.join(result_pathname, filename)
69
+ end
70
+
71
+ def generate_attrs(attrs)
72
+ %w(id align float title role width height alt)
73
+ .reduce({}) do |memo, key|
74
+ memo[key] = attrs[key] if attrs.has_key? key
75
+ memo
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -1,86 +1,31 @@
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(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
41
22
 
42
- def lutaml_temp(reader)
43
- temp_file = Tempfile.new(["lutaml", ".lutaml"])
23
+ def lutaml_temp(document, reader)
24
+ temp_file = Tempfile.new(["lutaml", ".lutaml"], Utils.relative_file_path(document, ''))
44
25
  temp_file.puts(reader.read)
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
@@ -14,7 +14,7 @@ module Metanorma
14
14
  # @example [lutaml_uml_attributes_table,path/to/lutaml,EntityName]
15
15
  class LutamlUmlAttributesTablePreprocessor < Asciidoctor::Extensions::Preprocessor
16
16
  MARCO_REGEXP =
17
- /\[lutaml_uml_attributes_table,([^,]+),?(.+)?,([^,]+),?(.+)?\]/
17
+ /\[lutaml_uml_attributes_table,([^,]+),?([^,]+),?(.+?)?\]/
18
18
  # search document for block `datamodel_attributes_table`
19
19
  # read include derectives that goes after that in block and transform
20
20
  # into yaml2text blocks
@@ -36,15 +36,16 @@ module Metanorma
36
36
  input_lines.each_with_object([]) do |line, result|
37
37
  if match = line.match(MARCO_REGEXP)
38
38
  lutaml_path = match[1]
39
- entity_name = match[3]
40
- result.push(*parse_marco(lutaml_path, entity_name, document))
39
+ entity_name = match[2]
40
+ skip_headers = match[3]
41
+ result.push(*parse_marco(lutaml_path, entity_name, document, skip_headers))
41
42
  else
42
43
  result.push(line)
43
44
  end
44
45
  end
45
46
  end
46
47
 
47
- def parse_marco(lutaml_path, entity_name, document)
48
+ def parse_marco(lutaml_path, entity_name, document, skip_headers)
48
49
  lutaml_document = lutaml_document_from_file(document, lutaml_path)
49
50
  .serialized_document
50
51
  entities = [lutaml_document["classes"], lutaml_document["enums"]]
@@ -53,12 +54,12 @@ module Metanorma
53
54
  entity_definition = entities.detect do |klass|
54
55
  klass["name"] == entity_name.strip
55
56
  end
56
- model_representation(entity_definition, document)
57
+ model_representation(entity_definition, document, skip_headers)
57
58
  end
58
59
 
59
- def model_representation(entity_definition, document)
60
+ def model_representation(entity_definition, document, skip_headers)
60
61
  render_result, errors = Utils.render_liquid_string(
61
- template_string: table_template,
62
+ template_string: table_template(skip_headers),
62
63
  context_items: entity_definition,
63
64
  context_name: "definition",
64
65
  document: document
@@ -68,9 +69,9 @@ module Metanorma
68
69
  end
69
70
 
70
71
  # rubocop:disable Layout/IndentHeredoc
71
- def table_template
72
+ def table_template(skip_headers)
72
73
  <<~TEMPLATE
73
- === {{ definition.name }}
74
+ #{"=== {{ definition.name }}" unless skip_headers}
74
75
  {{ definition.definition }}
75
76
 
76
77
  {% if definition.attributes %}
@@ -89,7 +90,7 @@ module Metanorma
89
90
  |Name |Definition |Mandatory/ Optional/ Conditional |Max Occur |Data Type
90
91
 
91
92
  {% 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 }}`
93
+ |{{ 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
94
  {% endfor %}
94
95
  |===
95
96
  {% endif %}
@@ -0,0 +1,156 @@
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
+ LIQUID_INCLUDE_PATH = File.join(
20
+ Gem.loaded_specs["metanorma-plugin-lutaml"].full_gem_path,
21
+ "lib", "metanorma", "plugin", "lutaml", "liquid_templates"
22
+ )
23
+ # search document for block `lutaml_uml_datamodel_description`
24
+ # read include derectives that goes after that in block and transform
25
+ # into yaml2text blocks
26
+ def process(document, reader)
27
+ input_lines = reader.readlines.to_enum
28
+ Asciidoctor::Reader.new(processed_lines(document, input_lines))
29
+ end
30
+
31
+ private
32
+
33
+ def lutaml_document_from_file(document, file_path)
34
+ ::Lutaml::Parser
35
+ .parse(File.new(Utils.relative_file_path(document, file_path),
36
+ encoding: "UTF-8"))
37
+ .first
38
+ end
39
+
40
+ def parse_yaml_config_file(document, file_path)
41
+ return {} if file_path.nil?
42
+
43
+ relative_file_path = Utils.relative_file_path(document, file_path)
44
+ YAML.load(File.read(relative_file_path, encoding: "UTF-8"))
45
+ end
46
+
47
+ def processed_lines(document, input_lines)
48
+ result = []
49
+ loop do
50
+ result.push(*process_text_blocks(document, input_lines))
51
+ end
52
+ result
53
+ end
54
+
55
+ def process_text_blocks(document, input_lines)
56
+ line = input_lines.next
57
+ block_match = line.match(MARCO_REGEXP)
58
+ return [line] if block_match.nil?
59
+
60
+ model_representation(
61
+ lutaml_document_from_file(document, block_match[1]),
62
+ document,
63
+ collect_additional_context(input_lines, input_lines.next),
64
+ parse_yaml_config_file(document, block_match[2]))
65
+ end
66
+
67
+ def collect_additional_context(input_lines, end_mark)
68
+ additional_context = {}
69
+ block_lines = []
70
+ while (block_line = input_lines.next) != end_mark
71
+ block_lines.push(block_line)
72
+ end
73
+ block_document = (Asciidoctor::Document.new(block_lines, {})).parse
74
+ block_document.blocks.each do |block|
75
+ attrs = block.attributes
76
+ name = attrs.delete('role')
77
+ package = attrs.delete('package')
78
+ macro_keyword = [name, package].compact.join(";")
79
+ additional_context[macro_keyword] = { 'text' => block.lines[1..-2].join("\n") }.merge(attrs)
80
+ end
81
+ additional_context
82
+ end
83
+
84
+ def create_context_object(lutaml_document, additional_context, options)
85
+ if options.length.zero?
86
+ return {
87
+ 'render_nested_packages' => true,
88
+ "packages" => lutaml_document.to_liquid['packages'].first['packages'].first['packages'],
89
+ "additional_context" => additional_context
90
+ }
91
+ end
92
+
93
+ root_package = lutaml_document.to_liquid['packages'].first
94
+ all_packages = [root_package, *root_package['children_packages']]
95
+ {
96
+ "packages" => sort_and_filter_out_packages(all_packages, options),
97
+ "additional_context" => additional_context
98
+ }
99
+ end
100
+
101
+ def sort_and_filter_out_packages(all_packages, options)
102
+ return all_packages if options['packages'].nil?
103
+
104
+ result = []
105
+ # Step one - filter out all skipped packages
106
+ options['packages']
107
+ .find_all { |entity| entity.is_a?(Hash) && entity['skip'] }
108
+ .each do |entity|
109
+ entity_regexp = config_entity_regexp(entity['skip'])
110
+ all_packages
111
+ .delete_if {|package| package['name'] =~ entity_regexp }
112
+ end
113
+ # Step two - select supplied packages by pattern
114
+ options['packages']
115
+ .find_all { |entity| entity.is_a?(String) }
116
+ .each do |entity|
117
+ entity_regexp = config_entity_regexp(entity)
118
+ all_packages.each.with_index do |package|
119
+ if package['name'] =~ entity_regexp
120
+ result.push(package)
121
+ all_packages
122
+ .delete_if {|nest_package| nest_package['name'] == package['name'] }
123
+ end
124
+ end
125
+ end
126
+ result
127
+ end
128
+
129
+ def config_entity_regexp(entity)
130
+ additional_sym = '.*' if entity =~ /\*$/
131
+ %r{^#{Regexp.escape(entity.gsub('*', ''))}#{additional_sym}$}
132
+ end
133
+
134
+ def model_representation(lutaml_document, document, additional_context, options)
135
+ render_result, errors = Utils.render_liquid_string(
136
+ template_string: table_template,
137
+ context_items: create_context_object(lutaml_document,
138
+ additional_context,
139
+ options),
140
+ context_name: "context",
141
+ document: document,
142
+ include_path: LIQUID_INCLUDE_PATH
143
+ )
144
+ Utils.notify_render_errors(document, errors)
145
+ render_result.split("\n")
146
+ end
147
+
148
+ def table_template
149
+ <<~LIQUID
150
+ {% include "packages", depth: 2, context: context, additional_context: context.additional_context, render_nested_packages: context.render_nested_packages %}
151
+ LIQUID
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -1,5 +1,6 @@
1
1
  require "expressir/express/cache"
2
2
  require "metanorma/plugin/lutaml/liquid/custom_filters"
3
+ require "metanorma/plugin/lutaml/liquid/multiply_local_file_system"
3
4
 
4
5
  ::Liquid::Template.register_filter(Metanorma::Plugin::Lutaml::Liquid::CustomFilters)
5
6
 
@@ -22,10 +23,11 @@ module Metanorma
22
23
  end
23
24
 
24
25
  def render_liquid_string(template_string:, context_items:,
25
- context_name:, document:)
26
+ context_name:, document:, include_path: nil)
26
27
  liquid_template = ::Liquid::Template.parse(template_string)
27
28
  # Allow includes for the template
28
- liquid_template.registers[:file_system] = ::Liquid::LocalFileSystem.new(Utils.relative_file_path(document, ""))
29
+ include_paths = [Utils.relative_file_path(document, ""), include_path].compact
30
+ liquid_template.registers[:file_system] = ::Metanorma::Plugin::Lutaml::Liquid::LocalFileSystem.new(include_paths, ["_%s.liquid", "_%s.adoc"])
29
31
  rendered_string = liquid_template
30
32
  .render(context_name => context_items,
31
33
  strict_variables: true,
@@ -1,7 +1,7 @@
1
1
  module Metanorma
2
2
  module Plugin
3
3
  module Lutaml
4
- VERSION = "0.4.1".freeze
4
+ VERSION = "0.4.5".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.1
4
+ version: 0.4.5
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-05-05 00:00:00.000000000 Z
11
+ date: 2021-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -243,6 +243,8 @@ extra_rdoc_files: []
243
243
  files:
244
244
  - ".github/workflows/rake.yml"
245
245
  - ".gitignore"
246
+ - ".hound.yml"
247
+ - ".rubocop.yml"
246
248
  - CODE_OF_CONDUCT.md
247
249
  - Dockerfile
248
250
  - Gemfile
@@ -255,9 +257,18 @@ files:
255
257
  - lib/metanorma-plugin-lutaml.rb
256
258
  - lib/metanorma/plugin/lutaml/express_remarks_decorator.rb
257
259
  - lib/metanorma/plugin/lutaml/liquid/custom_filters.rb
260
+ - lib/metanorma/plugin/lutaml/liquid/multiply_local_file_system.rb
261
+ - lib/metanorma/plugin/lutaml/liquid_templates/_diagrams_block.liquid
262
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages.liquid
263
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_class.liquid
264
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_data_type.liquid
265
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_enum.liquid
266
+ - lib/metanorma/plugin/lutaml/lutaml_diagram_base.rb
258
267
  - lib/metanorma/plugin/lutaml/lutaml_diagram_block.rb
268
+ - lib/metanorma/plugin/lutaml/lutaml_diagram_block_macro.rb
259
269
  - lib/metanorma/plugin/lutaml/lutaml_preprocessor.rb
260
270
  - lib/metanorma/plugin/lutaml/lutaml_uml_attributes_table_preprocessor.rb
271
+ - lib/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor.rb
261
272
  - lib/metanorma/plugin/lutaml/utils.rb
262
273
  - lib/metanorma/plugin/lutaml/version.rb
263
274
  - metanorma-plugin-lutaml.gemspec