metanorma-plugin-lutaml 0.4.1 → 0.4.5

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: 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