metanorma-plugin-lutaml 0.7.37 → 0.7.39

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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +5 -1
  3. data/.gitignore +2 -1
  4. data/.rubocop.yml +11 -2
  5. data/.rubocop_todo.yml +238 -0
  6. data/CLAUDE.md +78 -0
  7. data/Gemfile +8 -12
  8. data/Gemfile.devel +2 -0
  9. data/Rakefile +17 -0
  10. data/docs/usages/enterprise_architect.adoc +17 -0
  11. data/docs/usages/express.adoc +55 -0
  12. data/lib/metanorma/plugin/lutaml/base_structured_text_preprocessor.rb +6 -6
  13. data/lib/metanorma/plugin/lutaml/data2_text_preprocessor.rb +1 -0
  14. data/lib/metanorma/plugin/lutaml/express_remarks_decorator.rb +2 -2
  15. data/lib/metanorma/plugin/lutaml/json2_text_preprocessor.rb +1 -0
  16. data/lib/metanorma/plugin/lutaml/liquid/multiply_local_file_system.rb +2 -2
  17. data/lib/metanorma/plugin/lutaml/liquid_templates/_klass_table.liquid +6 -6
  18. data/lib/metanorma/plugin/lutaml/lutaml_ea_diagram_block_macro.rb +1 -1
  19. data/lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb +164 -15
  20. data/lib/metanorma/plugin/lutaml/lutaml_ea_xmi_preprocessor.rb +2 -2
  21. data/lib/metanorma/plugin/lutaml/lutaml_enum_table_block_macro.rb +8 -42
  22. data/lib/metanorma/plugin/lutaml/lutaml_gml_dictionary_block.rb +1 -0
  23. data/lib/metanorma/plugin/lutaml/lutaml_klass_table_block_macro.rb +9 -42
  24. data/lib/metanorma/plugin/lutaml/lutaml_preprocessor.rb +8 -6
  25. data/lib/metanorma/plugin/lutaml/lutaml_table_inline_macro.rb +1 -0
  26. data/lib/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor.rb +2 -2
  27. data/lib/metanorma/plugin/lutaml/lutaml_xmi_uml_preprocessor.rb +2 -2
  28. data/lib/metanorma/plugin/lutaml/source_extractor.rb +3 -3
  29. data/lib/metanorma/plugin/lutaml/utils.rb +52 -8
  30. data/lib/metanorma/plugin/lutaml/version.rb +1 -1
  31. data/lib/metanorma/plugin/lutaml/yaml2_text_preprocessor.rb +1 -0
  32. data/metanorma-plugin-lutaml.gemspec +4 -4
  33. metadata +25 -11
  34. data/.hound.yml +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2322a39b5dc29e981cf64a1c383c7d53aee9e1b132412ea79fc91dfac88485aa
4
- data.tar.gz: b1199f54f2e895a3938b1711c1b36184fbb0bc68fd79e56a6bc9acac12979c2e
3
+ metadata.gz: ad20f1059d6fb886f3b8f8e209a5eb2053bd84cf197b4df0a6f28c32ceb05b76
4
+ data.tar.gz: ea0e8cdfdc56ada195921fbefff8256f67e702dba4685a001ba22051031bfc74
5
5
  SHA512:
6
- metadata.gz: a11578fe6890dbf07994ba86d55ae9eee7d7eac605907b0dde761570c48d1871de497418ca1adff80091fdd931b520dcedf68ff1fc20f0cedac1f26bc78062a0
7
- data.tar.gz: a7f983789b4b1afd9d4b1b01b1b2546218d1530e9c6ff4cdb8f0ffab0d7f6af83d1f2611fdda609d038c0616dfe1ea50e91b0a61b053000602d3f1685f61a5e1
6
+ metadata.gz: a72753313c88e6a7bc1388c764fe2f315faf4ff7447690dd5d6a8851f5fe15285d1b53629ff6c79db3ba53ec20e7cdb9d05242e1ef2b5e9fe7b6e69076cedad0
7
+ data.tar.gz: 98fbf0c36b867aae35acf710853ea74506bfc7835e8ed4368e9acedc84fe9f622f2cc44aae66fabc75bd49c9242487027d94239cec948972cf0e6117941e1ac2
@@ -10,6 +10,10 @@ on:
10
10
 
11
11
  jobs:
12
12
  rake:
13
- uses: metanorma/ci/.github/workflows/graphviz-rake.yml@main
13
+ uses: metanorma/ci/.github/workflows/generic-rake.yml@main
14
+ with:
15
+ setup-tools: graphviz
16
+ submodules: true
17
+ choco-cache: true
14
18
  secrets:
15
19
  pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
data/.gitignore CHANGED
@@ -5,4 +5,5 @@ test.err
5
5
 
6
6
  .rubocop-https--*
7
7
  .DS_Store
8
- .vscode
8
+ .vscode
9
+ *.log.txt
data/.rubocop.yml CHANGED
@@ -1,10 +1,19 @@
1
1
  # Auto-generated by Cimas: Do not edit it manually!
2
2
  # See https://github.com/metanorma/cimas
3
3
  inherit_from:
4
- - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
4
+ - https://raw.githubusercontent.com/riboseinc/oss-guides/main/ci/rubocop.yml
5
+ - .rubocop_todo.yml
6
+
7
+ inherit_mode:
8
+ merge:
9
+ - Exclude
5
10
 
6
11
  # local repo-specific modifications
7
12
  # ...
13
+ plugins:
14
+ - rubocop-rspec
15
+ - rubocop-performance
16
+ - rubocop-rake
8
17
 
9
18
  AllCops:
10
- TargetRubyVersion: 2.5
19
+ TargetRubyVersion: 3.0
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,238 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2026-05-12 14:53:16 UTC using RuboCop version 1.86.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # This cop supports safe autocorrection (--autocorrect).
11
+ Gemspec/RequireMFA:
12
+ Exclude:
13
+ - 'metanorma-plugin-lutaml.gemspec'
14
+
15
+ # Offense count: 1
16
+ # This cop supports safe autocorrection (--autocorrect).
17
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
18
+ # SupportedStyles: with_first_argument, with_fixed_indentation
19
+ Layout/ArgumentAlignment:
20
+ Exclude:
21
+ - 'lib/metanorma/plugin/lutaml/lutaml_klass_table_block_macro.rb'
22
+
23
+ # Offense count: 1
24
+ # This cop supports safe autocorrection (--autocorrect).
25
+ Layout/ClosingParenthesisIndentation:
26
+ Exclude:
27
+ - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb'
28
+
29
+ # Offense count: 1
30
+ # This cop supports safe autocorrection (--autocorrect).
31
+ Layout/EmptyLines:
32
+ Exclude:
33
+ - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb'
34
+
35
+ # Offense count: 1
36
+ # This cop supports safe autocorrection (--autocorrect).
37
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
38
+ # SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses
39
+ Layout/FirstArgumentIndentation:
40
+ Exclude:
41
+ - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb'
42
+
43
+ # Offense count: 9
44
+ # This cop supports safe autocorrection (--autocorrect).
45
+ # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
46
+ # URISchemes: http, https
47
+ Layout/LineLength:
48
+ Exclude:
49
+ - 'Rakefile'
50
+ - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb'
51
+ - 'lib/metanorma/plugin/lutaml/lutaml_klass_table_block_macro.rb'
52
+ - 'lib/metanorma/plugin/lutaml/utils.rb'
53
+ - 'spec/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor_spec.rb'
54
+ - 'spec/support/shared_examples/structured_data_2_text_preprocessor.rb'
55
+
56
+ # Offense count: 1
57
+ # This cop supports safe autocorrection (--autocorrect).
58
+ # Configuration parameters: EnforcedStyle.
59
+ # SupportedStyles: symmetrical, new_line, same_line
60
+ Layout/MultilineMethodCallBraceLayout:
61
+ Exclude:
62
+ - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb'
63
+
64
+ # Offense count: 3
65
+ # This cop supports safe autocorrection (--autocorrect).
66
+ # Configuration parameters: AllowInHeredoc.
67
+ Layout/TrailingWhitespace:
68
+ Exclude:
69
+ - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb'
70
+ - 'lib/metanorma/plugin/lutaml/lutaml_klass_table_block_macro.rb'
71
+
72
+ # Offense count: 1
73
+ # This cop supports safe autocorrection (--autocorrect).
74
+ # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions.
75
+ # NotImplementedExceptions: NotImplementedError
76
+ Lint/UnusedMethodArgument:
77
+ Exclude:
78
+ - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb'
79
+
80
+ # Offense count: 1
81
+ # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
82
+ Metrics/AbcSize:
83
+ Exclude:
84
+ - 'lib/metanorma/plugin/lutaml/utils.rb'
85
+
86
+ # Offense count: 2
87
+ # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
88
+ Metrics/CyclomaticComplexity:
89
+ Exclude:
90
+ - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb'
91
+ - 'lib/metanorma/plugin/lutaml/utils.rb'
92
+
93
+ # Offense count: 3
94
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
95
+ Metrics/MethodLength:
96
+ Max: 19
97
+
98
+ # Offense count: 2
99
+ # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
100
+ Metrics/PerceivedComplexity:
101
+ Exclude:
102
+ - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb'
103
+ - 'lib/metanorma/plugin/lutaml/utils.rb'
104
+
105
+ # Offense count: 1
106
+ # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
107
+ # AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
108
+ Naming/MethodParameterName:
109
+ Exclude:
110
+ - 'lib/metanorma/plugin/lutaml/utils.rb'
111
+
112
+ # Offense count: 2
113
+ # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
114
+ # AllowedMethods: call
115
+ # WaywardPredicates: infinite?, nonzero?
116
+ Naming/PredicateMethod:
117
+ Exclude:
118
+ - 'lib/metanorma/plugin/lutaml/asciidoctor/preprocessor.rb'
119
+ - 'lib/metanorma/plugin/lutaml/liquid/custom_filters/file_exist.rb'
120
+
121
+ # Offense count: 1
122
+ # This cop supports unsafe autocorrection (--autocorrect-all).
123
+ Performance/AncestorsInclude:
124
+ Exclude:
125
+ - 'lib/metanorma/plugin/lutaml/utils.rb'
126
+
127
+ # Offense count: 86
128
+ # Configuration parameters: Prefixes, AllowedPatterns.
129
+ # Prefixes: when, with, without
130
+ RSpec/ContextWording:
131
+ Exclude:
132
+ - 'spec/metanorma/plugin/lutaml/lutaml_ea_xmi_preprocessor_spec.rb'
133
+ - 'spec/metanorma/plugin/lutaml/lutaml_enum_table_block_macro_spec.rb'
134
+ - 'spec/metanorma/plugin/lutaml/lutaml_gml_dictionary_block_macro_spec.rb'
135
+ - 'spec/metanorma/plugin/lutaml/lutaml_gml_dictionary_block_spec.rb'
136
+ - 'spec/metanorma/plugin/lutaml/lutaml_klass_table_block_macro_spec.rb'
137
+ - 'spec/metanorma/plugin/lutaml/lutaml_text_preprocessor_spec.rb'
138
+ - 'spec/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor_spec.rb'
139
+ - 'spec/metanorma/plugin/lutaml/lutaml_xmi_index_spec.rb'
140
+ - 'spec/metanorma/plugin/lutaml/lutaml_xmi_uml_preprocessor_spec.rb'
141
+ - 'spec/metanorma/plugin/lutaml/macros_data2text_spec.rb'
142
+ - 'spec/support/shared_examples/structured_data_2_text_preprocessor.rb'
143
+
144
+ # Offense count: 37
145
+ # Configuration parameters: CountAsOne.
146
+ RSpec/ExampleLength:
147
+ Max: 26
148
+
149
+ # Offense count: 13
150
+ # Configuration parameters: Max, AllowedIdentifiers, AllowedPatterns.
151
+ RSpec/IndexedLet:
152
+ Exclude:
153
+ - 'spec/metanorma/plugin/lutaml/lutaml_ea_diagram_block_macro_spec.rb'
154
+ - 'spec/metanorma/plugin/lutaml/lutaml_xmi_index_spec.rb'
155
+ - 'spec/metanorma/plugin/lutaml/macros_data2text_spec.rb'
156
+ - 'spec/support/shared_examples/structured_data_2_text_preprocessor.rb'
157
+
158
+ # Offense count: 4
159
+ # Configuration parameters: AssignmentOnly.
160
+ RSpec/InstanceVariable:
161
+ Exclude:
162
+ - 'spec/metanorma/plugin/lutaml/lutaml_express_preprocessor_spec.rb'
163
+
164
+ # Offense count: 44
165
+ RSpec/LeakyLocalVariable:
166
+ Exclude:
167
+ - 'spec/metanorma/plugin/lutaml/lutaml_ea_xmi_preprocessor_spec.rb'
168
+ - 'spec/metanorma/plugin/lutaml/lutaml_klass_table_block_macro_spec.rb'
169
+ - 'spec/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor_spec.rb'
170
+ - 'spec/metanorma/plugin/lutaml/lutaml_xmi_index_spec.rb'
171
+
172
+ # Offense count: 14
173
+ RSpec/MultipleExpectations:
174
+ Max: 6
175
+
176
+ # Offense count: 9
177
+ # Configuration parameters: AllowSubject.
178
+ RSpec/MultipleMemoizedHelpers:
179
+ Max: 8
180
+
181
+ # Offense count: 41
182
+ # Configuration parameters: EnforcedStyle, IgnoreSharedExamples.
183
+ # SupportedStyles: always, named_only
184
+ RSpec/NamedSubject:
185
+ Exclude:
186
+ - 'spec/metanorma/plugin/lutaml/config/root_spec.rb'
187
+ - 'spec/metanorma/plugin/lutaml/lutaml_ea_xmi_preprocessor_spec.rb'
188
+ - 'spec/metanorma/plugin/lutaml/lutaml_gml_dictionary_block_macro_spec.rb'
189
+ - 'spec/metanorma/plugin/lutaml/lutaml_gml_dictionary_block_spec.rb'
190
+ - 'spec/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor_spec.rb'
191
+ - 'spec/metanorma/plugin/lutaml/lutaml_xmi_index_spec.rb'
192
+ - 'spec/metanorma/plugin/lutaml/source_extractor_spec.rb'
193
+
194
+ # Offense count: 117
195
+ # Configuration parameters: AllowedGroups.
196
+ RSpec/NestedGroups:
197
+ Max: 7
198
+
199
+ # Offense count: 1
200
+ RSpec/PendingWithoutReason:
201
+ Exclude:
202
+ - 'spec/metanorma/plugin/lutaml/lutaml_text_preprocessor_spec.rb'
203
+
204
+ # Offense count: 2
205
+ RSpec/RepeatedExampleGroupBody:
206
+ Exclude:
207
+ - 'spec/metanorma/plugin/lutaml/macros_yaml2text_spec.rb'
208
+
209
+ # Offense count: 6
210
+ # Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
211
+ # SupportedInflectors: default, active_support
212
+ RSpec/SpecFilePathFormat:
213
+ Exclude:
214
+ - 'spec/metanorma/plugin/lutaml/lutaml_express_preprocessor_spec.rb'
215
+ - 'spec/metanorma/plugin/lutaml/lutaml_text_preprocessor_spec.rb'
216
+ - 'spec/metanorma/plugin/lutaml/lutaml_xmi_index_spec.rb'
217
+ - 'spec/metanorma/plugin/lutaml/macros_data2text_spec.rb'
218
+ - 'spec/metanorma/plugin/lutaml/macros_json2text_spec.rb'
219
+ - 'spec/metanorma/plugin/lutaml/macros_yaml2text_spec.rb'
220
+
221
+ # Offense count: 1
222
+ RSpec/SubjectDeclaration:
223
+ Exclude:
224
+ - 'spec/metanorma/plugin/lutaml/config/root_spec.rb'
225
+
226
+ # Offense count: 1
227
+ # This cop supports safe autocorrection (--autocorrect).
228
+ Style/RedundantBegin:
229
+ Exclude:
230
+ - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb'
231
+
232
+ # Offense count: 1
233
+ # This cop supports safe autocorrection (--autocorrect).
234
+ # Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
235
+ # SupportedStyles: single_quotes, double_quotes
236
+ Style/StringLiterals:
237
+ Exclude:
238
+ - 'metanorma-plugin-lutaml.gemspec'
data/CLAUDE.md ADDED
@@ -0,0 +1,78 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ `metanorma-plugin-lutaml` is a Ruby gem that provides Asciidoctor extensions for the Metanorma document publishing system. It enables Metanorma documents to embed and render data models from multiple formats: EXPRESS (ISO 10303), LutaML DSL, Enterprise Architect XMI, GML Dictionaries, JSON, and YAML.
8
+
9
+ ## Build and Test Commands
10
+
11
+ ```bash
12
+ # Install dependencies
13
+ bundle install
14
+
15
+ # Run all tests
16
+ bundle exec rake
17
+
18
+ # Run a single test file
19
+ bundle exec rspec spec/metanorma/plugin/lutaml/lutaml_preprocessor_spec.rb
20
+
21
+ # Run a specific test by line number
22
+ bundle exec rspec spec/metanorma/plugin/lutaml/lutaml_preprocessor_spec.rb:42
23
+
24
+ # Lint
25
+ bundle exec rubocop
26
+
27
+ # Build the gem
28
+ bundle exec rake build
29
+ ```
30
+
31
+ ## Architecture
32
+
33
+ ### Asciidoctor Extension Pattern
34
+
35
+ All extensions follow the Asciidoctor extension API. The two main extension types are:
36
+
37
+ - **Preprocessors** (`::Asciidoctor::Extensions::Preprocessor`): Process document text before rendering. They read input lines, detect custom block syntax (e.g., `[lutaml_express, ...]`), and replace them with rendered content via Liquid templates.
38
+ - **Block/BlockMacro/InlineMacro extensions**: Handle `lutaml_diagram`, `lutaml_ea_diagram`, `lutaml_gml_dictionary`, `lutaml_klass_table`, `lutaml_enum_table`, `lutaml_table`, `lutaml_figure` — these are Asciidoctor block-level or inline macros.
39
+
40
+ ### Preprocessor Inheritance Hierarchy
41
+
42
+ - `LutamlPreprocessor` — handles `[lutaml]`, `[lutaml_express]`, `[lutaml_express_liquid]` blocks. Parses EXPRESS files via the `lutaml`/`expressir` gems, builds Liquid contexts, and renders templates.
43
+ - `LutamlUmlDatamodelDescriptionPreprocessor` and `LutamlEaXmiPreprocessor` — both include `LutamlEaXmiBase`, which handles XMI parsing via `lutaml` gem and renders using bundled Liquid templates.
44
+ - `LutamlXmiUmlPreprocessor` — another XMI-based preprocessor with its own macro regex.
45
+ - `BaseStructuredTextPreprocessor` — base for `[yaml2text]`, `[json2text]`, `[data2text]` blocks. Its subclasses (`Yaml2TextPreprocessor`, `Json2TextPreprocessor`, `Data2TextPreprocessor`) differ only in how they load content (YAML vs JSON vs auto-detect). The `Content` module provides the actual parsing logic.
46
+
47
+ ### Key Shared Modules
48
+
49
+ - `Utils` (`lib/metanorma/plugin/lutaml/utils.rb`) — shared helpers: file path resolution relative to document, Liquid template rendering with custom environment/filters, EXPRESS repository loading with caching, parsing document-level `:lutaml-express-index:` attributes.
50
+ - `LutamlEaXmiBase` — shared logic for XMI-based preprocessors: XMI document loading/caching, config YAML parsing, package filtering/sorting, Liquid context building, nested macro collection.
51
+ - `LutamlDiagramBase` — shared logic for diagram block extensions: parses LutaML DSL, renders via Graphviz to PNG.
52
+ - `LutamlGmlDictionaryBase` — parses GML XML via `ogc-gml` gem, renders via Liquid.
53
+ - `SourceExtractor` — scans document lines for anchors (`[[id]]`, `[#id]`, `[id=...]`) and `include::`/`embed::` directives, extracting source blocks into `document.attributes["source_blocks"]` for later use by preprocessors.
54
+
55
+ ### Liquid Template System
56
+
57
+ The plugin uses Liquid templates extensively. Key components:
58
+
59
+ - **Custom Liquid environment** with registered `keyiterator` tag and custom filters (`html2adoc`, `values`, `replace_regex`, `loadfile`, `file_exist`).
60
+ - **`Liquid::LocalFileSystem`** subclass (`multiply_local_file_system.rb`) resolves includes from multiple paths.
61
+ - **Liquid Drops** (`liquid_drops/`) wrap domain objects (e.g., `GmlDictionaryDrop`) for template rendering.
62
+ - **Bundled templates** live in `lib/metanorma/plugin/lutaml/liquid_templates/` for XMI/EA rendering.
63
+
64
+ ### Config System
65
+
66
+ The `Config` module (`lib/metanorma/plugin/lutaml/config.rb`) uses `lutaml/model` (LutaML::Model) to define config schemas: `Root`, `Package`, `Guidance`, `GuidanceKlass`, `GuidanceAttribute`. Config YAML files control which packages/entities to render from XMI documents.
67
+
68
+ ### Testing Pattern
69
+
70
+ Tests use `metanorma-standoc` as the backend. The spec helper registers all extensions with Asciidoctor, then tests call `metanorma_convert(input)` which converts AsciiDoc input through the pipeline and compares XML output. Test fixtures (`.exp`, `.lutaml`, `.xmi`, `.xml`, `.liquid` files) are in `spec/fixtures/lutaml/` and `spec/assets/lutaml/`.
71
+
72
+ ## Key Dependencies
73
+
74
+ - `lutaml` — core LutaML parser/model library (EXPRESS, UML, XMI formats)
75
+ - `expressir` — EXPRESS schema parser
76
+ - `ogc-gml` — OGC GML dictionary parser
77
+ - `liquid` — template rendering engine
78
+ - `asciidoctor` — document processing framework
data/Gemfile CHANGED
@@ -12,18 +12,14 @@ rescue StandardError
12
12
  nil
13
13
  end
14
14
 
15
- gem "byebug"
16
- gem "debug"
17
- gem "equivalent-xml"
18
- gem "metanorma"
19
- gem "metanorma-standoc", "~> 3.0.8"
20
15
  gem "rake", "~> 13"
21
- gem "rspec", "~> 3.6"
16
+ gem "rspec"
22
17
  gem "rspec-html-matchers"
23
- gem "rubocop", "~> 1.58"
24
- gem "rubocop-performance", "~> 1.19"
25
- gem "simplecov", "~> 0.15"
26
- gem "timecop", "~> 0.9"
27
- gem "vcr", "~> 6.1.0"
18
+ gem "rubocop"
19
+ gem "rubocop-performance"
20
+ gem "rubocop-rake"
21
+ gem "rubocop-rspec"
22
+ gem "simplecov"
23
+ gem "timecop"
24
+ gem "vcr"
28
25
  gem "webmock"
29
- gem "xml-c14n"
data/Gemfile.devel ADDED
@@ -0,0 +1,2 @@
1
+ gem "metanorma-standoc", github: "metanorma/metanorma-standoc", branch: "main"
2
+ gem "metanorma", github: "metanorma/metanorma", branch: "main"
data/Rakefile CHANGED
@@ -1,6 +1,23 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
3
 
4
+ XMI_SPEC_FILES = %w[
5
+ spec/metanorma/plugin/lutaml/lutaml_ea_xmi_preprocessor_spec.rb
6
+ spec/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor_spec.rb
7
+ spec/metanorma/plugin/lutaml/lutaml_klass_table_block_macro_spec.rb
8
+ spec/metanorma/plugin/lutaml/lutaml_enum_table_block_macro_spec.rb
9
+ spec/metanorma/plugin/lutaml/lutaml_xmi_index_spec.rb
10
+ spec/metanorma/plugin/lutaml/lutaml_xmi_uml_preprocessor_spec.rb
11
+ ].freeze
12
+
4
13
  RSpec::Core::RakeTask.new(:spec)
5
14
 
15
+ RSpec::Core::RakeTask.new(:fast) do |t|
16
+ t.pattern = FileList["spec/**/*_spec.rb"] - XMI_SPEC_FILES
17
+ end
18
+
19
+ RSpec::Core::RakeTask.new(:xmi) do |t|
20
+ t.pattern = FileList[XMI_SPEC_FILES]
21
+ end
22
+
6
23
  task default: :spec
@@ -184,6 +184,15 @@ The command accepts the options listed below:
184
184
  `lib/metanorma/plugin/lutaml/templates`. This template can be customized by
185
185
  changing the template path in the `template` option.
186
186
 
187
+ * `external_data="context_name:/path/to/my_data.yml"` specifies the path of
188
+ the YAML/JSON file of the external data to be used in the liquid template.
189
+ (Optional)
190
+ You can specify multiple external data by separating them with `;`.
191
+ (e.g. `external_data="my_data:/path/to/my_data.yml;second_data:/path/to/my_second_data.yml"`)
192
+ In the liquid template, you can access the data by using `context_name`.
193
+ (e.g. `my_data` or `second_data` in the above example)
194
+ The external data file should be in YAML/JSON format.
195
+
187
196
  * `guidance="/path/to/my_guidance.yml"` specifies the path of
188
197
  the yaml file of the guidance. (Optional)
189
198
 
@@ -240,6 +249,14 @@ The command accepts the options listed below:
240
249
  `lib/metanorma/plugin/lutaml/templates`. This template can be customized by
241
250
  changing the template path in the `template` option.
242
251
 
252
+ * `external_data="context_name:/path/to/my_data.yml"` specifies the path of
253
+ the YAML/JSON file of the external data to be used in the liquid template.
254
+ (Optional)
255
+ You can specify multiple external data by separating them with `;`.
256
+ (e.g. `external_data="my_data:/path/to/my_data.yml;second_data:/path/to/my_second_data.yml"`)
257
+ In the liquid template, you can access the data by using `context_name`.
258
+ (e.g. `my_data` or `second_data` in the above example)
259
+ The external data file should be in YAML/JSON format.
243
260
 
244
261
  === Usage of `lutaml_ea_xmi` command
245
262
 
@@ -297,3 +297,58 @@ from the paths other than the location of the document.
297
297
  The resulting block adds the `include_path` to the Liquid renderer. The path is
298
298
  resolved based on the location of the document. You can add multiple paths by
299
299
  separating them with commas.
300
+
301
+ === Using `loadfile` filter in templates
302
+
303
+ This functionality allows `[lutaml_express_liquid]` blocks to load data from
304
+ a yaml or json file from the specified path.
305
+
306
+ For example, you have the Metanorma document file (.adoc) with the following
307
+ content:
308
+
309
+ [source,adoc]
310
+ -----
311
+ :lutaml-express-index: all_schemas; ../schemas_all.yaml;
312
+
313
+ [lutaml_express_liquid,all_schemas,context,config_yaml=schemas.yaml,include_path=../templates]
314
+ ---
315
+ {% assign all_schemas = repo.schemas %}
316
+ {% render "templates/resources/schema" for ordered_schemas as schema %}
317
+ ...
318
+ ----
319
+ -----
320
+
321
+ You have the liquid template file
322
+ `templates/resources/schema.liquid` with the following content:
323
+
324
+ [source,liquid]
325
+ -----
326
+ {% assign data = "my_file.yaml" | loadfile: "." %}
327
+ This is {{ data.shape }} with color {{ data.color }}.
328
+ -----
329
+
330
+ Where:
331
+
332
+ * `loadfile:` is a liquid filter that loads the file content based on the path
333
+ `my_file.yaml` with argument `.`.
334
+ The argument is the path of the parent folder, which is the
335
+ current directory of the Metanorma document.
336
+
337
+ And the content of the yaml file `my_file.yaml` looks like:
338
+
339
+ [source,yaml]
340
+ ----
341
+ ---
342
+ shape: square
343
+ color: blue
344
+ corners: 4
345
+ ----
346
+
347
+ Will render as:
348
+ [source,asciidoc]
349
+ ----
350
+ ...
351
+ This is square with color blue.
352
+ ...
353
+ ----
354
+
@@ -15,9 +15,9 @@ module Metanorma
15
15
  ::Asciidoctor::Extensions::Preprocessor
16
16
  include Utils
17
17
 
18
- BLOCK_START_REGEXP = /\{(.+?)\.\*,(.+),(.+)\}/.freeze
19
- BLOCK_END_REGEXP = /\A\{[A-Z]+\}\z/.freeze
20
- LOAD_FILE_REGEXP = /{% assign (.*) = (.*) \| load_file %}/.freeze
18
+ BLOCK_START_REGEXP = /\{(.+?)\.\*,(.+),(.+)\}/
19
+ BLOCK_END_REGEXP = /\A\{[A-Z]+\}\z/
20
+ LOAD_FILE_REGEXP = /{% assign (.*) = (.*) \| load_file %}/
21
21
  INCLUDE_PATH_OPTION = "include_path"
22
22
  TEMPLATE_OPTION = "template"
23
23
 
@@ -63,7 +63,7 @@ module Metanorma
63
63
  load_file_match = block_line.match(LOAD_FILE_REGEXP)
64
64
 
65
65
  # Add parent folder as argument to loadfile filter
66
- block_line = "{% assign #{load_file_match[1]} = "\
66
+ block_line = "{% assign #{load_file_match[1]} = " \
67
67
  "#{load_file_match[2]} | loadfile: " \
68
68
  "\"#{document.attributes['docdir']}\" %}"
69
69
  end
@@ -106,7 +106,7 @@ module Metanorma
106
106
  )
107
107
  multiple_contexts
108
108
  elsif block_match[1].start_with?("#")
109
- anchor = block_match[1].split(",").first.strip[1..-1]
109
+ anchor = block_match[1].split(",").first.strip[1..]
110
110
  {
111
111
  block_match[1].split(",").last.strip =>
112
112
  content_from_anchor(document, anchor),
@@ -153,7 +153,7 @@ module Metanorma
153
153
  end
154
154
  line
155
155
  .gsub(/(?<!{){(?!%)([^{}]{1,900})(?<!%)}(?!})/, '{{\1}}')
156
- .gsub(/[a-z\.]{1,900}\#/, "index")
156
+ .gsub(/[a-z.]{1,900}\#/, "index")
157
157
  .gsub(/{{([^}]{1,900})\s+\+\s+(\d+)\s*?}}/, '{{ \1 | plus: \2 }}')
158
158
  .gsub(/{{([^}]{1,900})\s+-\s+(\d+)\s*?}}/, '{{ \1 | minus: \2 }}')
159
159
  .gsub(/{{([^}]{1,500})\.values([^}]{0,500})}}/,
@@ -8,6 +8,7 @@ module Metanorma
8
8
  module Lutaml
9
9
  class Data2TextPreprocessor < BaseStructuredTextPreprocessor
10
10
  include Content
11
+
11
12
  # search document for block `data2text`
12
13
  # after that take template from block and read file into this template
13
14
  # example:
@@ -9,14 +9,14 @@ module Metanorma
9
9
  (link|image|video|audio|include) # Capture group 1: content type
10
10
  (:+)? # Capture group 2: optional colons
11
11
  (?! # Negative lookahead
12
- [^\/:]+://| # Don't match URLs (http://, etc.)
12
+ [^/:]+://| # Don't match URLs (http://, etc.)
13
13
  [A-Z]:/| # Don't match Windows paths
14
14
  / # Don't match absolute paths
15
15
  ) # End negative lookahead
16
16
  ([^:\[]+) # Capture group 3: the path/name
17
17
  (\[.*\])? # Capture group 4: optional attribute
18
18
  $ # End of line
19
- }x.freeze
19
+ }x
20
20
 
21
21
  attr_reader :remark, :options
22
22
 
@@ -8,6 +8,7 @@ module Metanorma
8
8
  module Lutaml
9
9
  class Json2TextPreprocessor < BaseStructuredTextPreprocessor
10
10
  include Content
11
+
11
12
  # search document for block `json2text`
12
13
  # after that take template from block and read file into this template
13
14
  # example:
@@ -52,8 +52,8 @@ module Metanorma
52
52
 
53
53
  if result_path.nil?
54
54
  raise ::Liquid::FileSystemError,
55
- "No documents in template path: " \
56
- " #{File.expand_path(template_path)}"
55
+ "No documents in template path: " \
56
+ "#{File.expand_path(template_path)}"
57
57
  end
58
58
 
59
59
  unless roots.any? do |root|
@@ -22,7 +22,7 @@ h| Stereotype 2+| {{ stereotype }}
22
22
  3+h| Inherited Properties
23
23
  h| Property Name h| Property Type and Multiplicity h| Definition
24
24
  {% for attr in root.inherited_props %}
25
- {%- if attr.has_association? == false -%}
25
+ {%- unless attr.has_association? -%}
26
26
  {%- capture name_col -%}
27
27
  {{ attr.name_ns }}:{{ attr.name }}
28
28
  ({{ attr.gen_name }})
@@ -30,13 +30,13 @@ h| Property Name h| Property Type and Multiplicity h| Definition
30
30
  | {{ name_col | newline_to_br }}
31
31
  | {{ attr.type }} [{{ attr.cardinality.min }}..{{ attr.cardinality.max }}]
32
32
  | {{ attr.definition }}
33
- {%- endif -%}
33
+ {%- endunless -%}
34
34
  {% endfor %}
35
35
 
36
36
  3+h| Self-defined Properties
37
37
  h| Property Name h| Property Type and Multiplicity h| Definition
38
38
  {% for attr in root.owned_props %}
39
- {%- if attr.has_association? == false -%}
39
+ {%- unless attr.has_association? -%}
40
40
  {%- capture name_col -%}
41
41
  {{ attr.name_ns }}:{{ attr.name }}
42
42
  ({{ attr.gen_name }})
@@ -44,13 +44,13 @@ h| Property Name h| Property Type and Multiplicity h| Definition
44
44
  | {{ name_col | newline_to_br }}
45
45
  | {{ attr.type }} [{{ attr.cardinality.min }}..{{ attr.cardinality.max }}]
46
46
  | {{ attr.definition }}
47
- {%- endif -%}
47
+ {%- endunless -%}
48
48
  {% endfor %}
49
49
 
50
50
  3+h| Properties Inherited from Association
51
51
  h| Property Name h| Property Type and Multiplicity h| Definition
52
52
  {% for attr in root.inherited_assoc_props %}
53
- {%- if attr.has_association? == true -%}
53
+ {%- if attr.has_association? -%}
54
54
  {%- capture name_col -%}
55
55
  {{ attr.name_ns }}:{{ attr.name }}
56
56
  ({{ attr.gen_name }})
@@ -64,7 +64,7 @@ h| Property Name h| Property Type and Multiplicity h| Definition
64
64
  3+h| Properties Defined in Association
65
65
  h| Property Name h| Property Type and Multiplicity h| Definition
66
66
  {% for attr in root.assoc_props %}
67
- {%- if attr.has_association? == true -%}
67
+ {%- if attr.has_association? -%}
68
68
  {%- capture name_col -%}
69
69
  {{ attr.name_ns }}:{{ attr.name }}
70
70
  ({{ attr.gen_name }})
@@ -29,7 +29,7 @@ module Metanorma
29
29
  private
30
30
 
31
31
  def parse_result_document(full_path, guidance = nil)
32
- ::Lutaml::XMI::Parsers::XML.serialize_xmi_to_liquid(
32
+ ::Lutaml::Xmi::Parsers::Xml.serialize_xmi_to_liquid(
33
33
  File.new(full_path, encoding: "UTF-8"),
34
34
  guidance,
35
35
  )