lutaml-model 0.8.18 → 0.8.22

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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-tests.yml +1 -1
  3. data/.github/workflows/rake.yml +1 -0
  4. data/.rubocop.yml +1 -1
  5. data/.rubocop_todo.yml +133 -72
  6. data/bench/bench_common.rb +8 -5
  7. data/bench/bench_niso.rb +1 -2
  8. data/bench/gate_config.rb +4 -1
  9. data/benchmark/serialization_benchmark.rb +4 -4
  10. data/docs/_guides/builder-dsl.adoc +127 -0
  11. data/docs/_guides/value-transformations.adoc +27 -0
  12. data/lib/compat/opal/generate_boot.rb +3 -1
  13. data/lib/compat/opal/lutaml_model_boot.rb +10 -7
  14. data/lib/compat/opal/moxml_boot.rb +6 -1
  15. data/lib/lutaml/hash_format/format.rb +29 -0
  16. data/lib/lutaml/hash_format.rb +5 -27
  17. data/lib/lutaml/json/format.rb +61 -0
  18. data/lib/lutaml/json.rb +4 -59
  19. data/lib/lutaml/jsonl/format.rb +22 -0
  20. data/lib/lutaml/jsonl.rb +5 -19
  21. data/lib/lutaml/key_value/format.rb +26 -0
  22. data/lib/lutaml/key_value/transform.rb +4 -1
  23. data/lib/lutaml/key_value/transformation/value_serializer.rb +0 -2
  24. data/lib/lutaml/key_value.rb +4 -21
  25. data/lib/lutaml/model/attribute.rb +38 -4
  26. data/lib/lutaml/model/collection.rb +2 -2
  27. data/lib/lutaml/model/compiled_rule.rb +1 -1
  28. data/lib/lutaml/model/config.rb +2 -2
  29. data/lib/lutaml/model/consolidation_map.rb +2 -2
  30. data/lib/lutaml/model/consolidation_rule/dispatch_block.rb +2 -2
  31. data/lib/lutaml/model/errors.rb +2 -2
  32. data/lib/lutaml/model/global_context.rb +4 -2
  33. data/lib/lutaml/model/mapping/mapping_rule.rb +4 -1
  34. data/lib/lutaml/model/mapping/model_mapping.rb +2 -2
  35. data/lib/lutaml/model/runtime_compatibility.rb +2 -2
  36. data/lib/lutaml/model/schema/class_loader.rb +2 -1
  37. data/lib/lutaml/model/schema/decorators/definition_collection.rb +4 -4
  38. data/lib/lutaml/model/schema/definitions/namespace.rb +2 -1
  39. data/lib/lutaml/model/schema/file_writer.rb +5 -2
  40. data/lib/lutaml/model/schema/renderers/base.rb +4 -3
  41. data/lib/lutaml/model/schema/renderers/mappings.rb +9 -3
  42. data/lib/lutaml/model/schema/renderers/member_decls.rb +9 -3
  43. data/lib/lutaml/model/schema/renderers/model.rb +18 -6
  44. data/lib/lutaml/model/schema/renderers/required_files_calculator.rb +2 -1
  45. data/lib/lutaml/model/schema/renderers.rb +2 -1
  46. data/lib/lutaml/model/schema/rnc_compiler/source_resolver.rb +6 -2
  47. data/lib/lutaml/model/schema/rnc_compiler.rb +3 -1
  48. data/lib/lutaml/model/schema/rng_compiler/element_visitor.rb +35 -15
  49. data/lib/lutaml/model/schema/rng_compiler/value_type_resolver.rb +4 -2
  50. data/lib/lutaml/model/schema/rng_compiler.rb +10 -5
  51. data/lib/lutaml/model/schema/xml_compiler/element_order.rb +2 -1
  52. data/lib/lutaml/model/schema/xml_compiler/spec_builder/complex_types.rb +4 -2
  53. data/lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb +39 -13
  54. data/lib/lutaml/model/schema/xml_compiler/spec_builder.rb +29 -10
  55. data/lib/lutaml/model/schema/xml_compiler/supported_data_types.rb +2 -2
  56. data/lib/lutaml/model/schema/xml_compiler.rb +10 -5
  57. data/lib/lutaml/model/sequence.rb +4 -4
  58. data/lib/lutaml/model/serialize/attribute_definition.rb +10 -9
  59. data/lib/lutaml/model/serialize/builder.rb +55 -0
  60. data/lib/lutaml/model/serialize/format_conversion.rb +2 -2
  61. data/lib/lutaml/model/serialize/initialization.rb +12 -3
  62. data/lib/lutaml/model/serialize/model_import.rb +1 -0
  63. data/lib/lutaml/model/serialize.rb +4 -3
  64. data/lib/lutaml/model/type/uninitialized_class_guard.rb +1 -1
  65. data/lib/lutaml/model/type.rb +9 -0
  66. data/lib/lutaml/model/type_registry.rb +2 -2
  67. data/lib/lutaml/model/uninitialized_class.rb +1 -1
  68. data/lib/lutaml/model/union.rb +5 -2
  69. data/lib/lutaml/model/utils.rb +2 -2
  70. data/lib/lutaml/model/value_policy.rb +27 -0
  71. data/lib/lutaml/model/version.rb +1 -1
  72. data/lib/lutaml/model.rb +17 -16
  73. data/lib/lutaml/rdf/mapping.rb +2 -2
  74. data/lib/lutaml/rdf/namespace_set.rb +2 -2
  75. data/lib/lutaml/rdf/transform.rb +2 -2
  76. data/lib/lutaml/toml/format.rb +48 -0
  77. data/lib/lutaml/toml.rb +5 -46
  78. data/lib/lutaml/xml/adapter/base_adapter.rb +2 -2
  79. data/lib/lutaml/xml/builder/base.rb +2 -2
  80. data/lib/lutaml/xml/format.rb +331 -0
  81. data/lib/lutaml/xml/mapping.rb +2 -2
  82. data/lib/lutaml/xml/mapping_rule.rb +62 -3
  83. data/lib/lutaml/xml/model_transform.rb +132 -55
  84. data/lib/lutaml/xml/namespace_collector.rb +3 -3
  85. data/lib/lutaml/xml/parse_session.rb +59 -0
  86. data/lib/lutaml/xml/parsed_namespace_set.rb +2 -2
  87. data/lib/lutaml/xml/schema/builder.rb +5 -5
  88. data/lib/lutaml/xml/schema/xsd/schema_location_mapping.rb +2 -2
  89. data/lib/lutaml/xml/schema/xsd.rb +0 -2
  90. data/lib/lutaml/xml/schema/xsd_schema.rb +2 -1
  91. data/lib/lutaml/xml/serialization/format_conversion.rb +3 -3
  92. data/lib/lutaml/xml/transformation/element_builder.rb +2 -1
  93. data/lib/lutaml/xml/transformation/ordered_applier.rb +99 -4
  94. data/lib/lutaml/xml/xml_element.rb +2 -0
  95. data/lib/lutaml/xml.rb +4 -328
  96. data/lib/lutaml/yaml/format.rb +30 -0
  97. data/lib/lutaml/yaml.rb +5 -28
  98. data/lib/lutaml/yamls/adapter/mapping.rb +2 -2
  99. data/lib/lutaml/yamls/format.rb +22 -0
  100. data/lib/lutaml/yamls.rb +5 -19
  101. data/lib/tasks/benchmark_runner.rb +2 -2
  102. data/lutaml-model.gemspec +1 -1
  103. data/spec/lutaml/model/attribute_apply_value_map_spec.rb +26 -13
  104. data/spec/lutaml/model/attribute_spec.rb +8 -3
  105. data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +2 -2
  106. data/spec/lutaml/model/custom_from_empty_values_spec.rb +74 -0
  107. data/spec/lutaml/model/custom_vobject_adapter_spec.rb +8 -8
  108. data/spec/lutaml/model/defaults_spec.rb +45 -0
  109. data/spec/lutaml/model/json_spec.rb +1 -2
  110. data/spec/lutaml/model/ordered_content_spec.rb +18 -7
  111. data/spec/lutaml/model/serialize/builder_spec.rb +361 -0
  112. data/spec/lutaml/model/store_spec.rb +3 -1
  113. data/spec/lutaml/model/transform_apply_value_map_spec.rb +6 -3
  114. data/spec/lutaml/model/union_attribute_spec.rb +4 -2
  115. data/spec/lutaml/model/value_policy_spec.rb +82 -0
  116. data/spec/lutaml/require_load_order_spec.rb +25 -0
  117. data/spec/lutaml/xml/attribute_element_namespace_disjoint_spec.rb +88 -0
  118. data/spec/lutaml/xml/attribute_namespace_disjointness_spec.rb +125 -0
  119. data/spec/lutaml/xml/out_of_namespace_parsing_spec.rb +123 -0
  120. data/spec/lutaml/xml/schema/rnc_compiler_spec.rb +17 -6
  121. data/spec/lutaml/xml/schema/rng_compiler_spec.rb +15 -6
  122. data/spec/lutaml/xml/w3c_types_spec.rb +3 -6
  123. metadata +22 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 852a93ce391ef7eb0f8e7673bda66f7bb417637b252735cebe833d1e305a6c7b
4
- data.tar.gz: 65f067c3e0bf4e1d520d5e2d133a6de4606900844b5e91d367ce4edee51da0e1
3
+ metadata.gz: a30fcd552dca587769736a81de33b66909c592cbc5ed40f696d34fbaf7de887f
4
+ data.tar.gz: b15506fd1398cad525dcac0a624166cdc23dedf7faa3e282b1aae10c583b405a
5
5
  SHA512:
6
- metadata.gz: 318f15b16d919319fd4c2cd9c2722a1ee37b8f1a4272b5a966ce45bf2811447c7c1004642fd76c3204ddd70c8fb4ac6de9397e67f7305529e4b2310769fca52b
7
- data.tar.gz: 65479ec0a4e9ef58938953f94802da282bfe2d443c4d7cd41a9bf83973e653c3d6ce700fb9eb07e7e5cf1ffa120cfb54fded8d71d8215f4e35c76360dd6393fe
6
+ metadata.gz: 061ea9253cc7e425f9591e5f57407935eb6b52b1ee69fc5b289b672a0109f8aa3850097d0dd3971613b6010c5e8d83b5425e3447bebe0ae6724916fbdc7a3173
7
+ data.tar.gz: 9280bc8adfdeaa2e6167c57379d0d40a7c8c27a4dffb420c8f8b6468b893df8ae72207d5fddef2885d4954ba4c45918a1f9cd3746ef2194aed3b09bae46b19f9
@@ -22,7 +22,7 @@ jobs:
22
22
  uses: metanorma/ci/.github/workflows/dependent-rake.yml@main
23
23
  with:
24
24
  command: bundle exec rspec
25
- setup-tools: 'inkscape,ghostscript,exiftool,ffmpeg,imagemagick'
25
+ setup-tools: 'inkscape,ghostscript,exiftool,ffmpeg,imagemagick,yq'
26
26
  after-setup-ruby: |
27
27
  if [ -f frontend/package.json ]; then cd frontend && npm install && npm run build; fi
28
28
  secrets:
@@ -25,6 +25,7 @@ jobs:
25
25
  experimental: [false]
26
26
  include:
27
27
  - os: windows-latest
28
+ ruby: head
28
29
  experimental: true
29
30
  steps:
30
31
  - uses: actions/checkout@v6
data/.rubocop.yml CHANGED
@@ -8,7 +8,7 @@ plugins:
8
8
  - rubocop-rspec
9
9
 
10
10
  AllCops:
11
- TargetRubyVersion: 3.2
11
+ TargetRubyVersion: 3.0
12
12
  NewCops: enable
13
13
  Exclude:
14
14
  - 'vendor/**/*'
data/.rubocop_todo.yml CHANGED
@@ -1,75 +1,134 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-06-08 11:45:37 UTC using RuboCop version 1.87.0.
3
+ # on 2026-08-25 07:32:39 UTC using RuboCop version 1.90.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 1
10
- Gemspec/RequiredRubyVersion:
11
- Exclude:
12
- - 'lutaml-model.gemspec'
13
-
14
- # Offense count: 1
9
+ # Offense count: 88
15
10
  # This cop supports safe autocorrection (--autocorrect).
16
11
  # Configuration parameters: EnforcedStyle, IndentationWidth.
17
12
  # SupportedStyles: with_first_argument, with_fixed_indentation
18
13
  Layout/ArgumentAlignment:
14
+ Enabled: false
15
+
16
+ # Offense count: 3
17
+ # This cop supports safe autocorrection (--autocorrect).
18
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
19
+ # SupportedStyles: with_first_element, with_fixed_indentation
20
+ Layout/ArrayAlignment:
19
21
  Exclude:
20
- - 'lib/lutaml/rdf/linked_data_transform.rb'
22
+ - 'spec/lutaml/model/serialize/builder_spec.rb'
23
+ - 'spec/lutaml/model/union_attribute_spec.rb'
21
24
 
22
- # Offense count: 2
25
+ # Offense count: 7
26
+ # This cop supports safe autocorrection (--autocorrect).
27
+ # Configuration parameters: IndentationWidth.
28
+ Layout/AssignmentIndentation:
29
+ Exclude:
30
+ - 'lib/lutaml/model/schema/xml_compiler/element_order.rb'
31
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder.rb'
32
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb'
33
+
34
+ # Offense count: 25
23
35
  # This cop supports safe autocorrection (--autocorrect).
24
36
  # Configuration parameters: EnforcedStyleAlignWith.
25
37
  # SupportedStylesAlignWith: either, start_of_block, start_of_line
26
38
  Layout/BlockAlignment:
27
39
  Exclude:
28
- - 'spec/lutaml/model/choice_restrict_spec.rb'
40
+ - 'lib/compat/opal/generate_boot.rb'
41
+ - 'lib/lutaml/model/schema/file_writer.rb'
42
+ - 'lib/lutaml/model/schema/renderers/mappings.rb'
43
+ - 'lib/lutaml/model/schema/renderers/member_decls.rb'
44
+ - 'lib/lutaml/model/schema/rnc_compiler.rb'
45
+ - 'lib/lutaml/model/schema/rng_compiler.rb'
46
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder.rb'
47
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb'
48
+ - 'lib/lutaml/model/union.rb'
49
+ - 'spec/lutaml/model/attribute_spec.rb'
50
+ - 'spec/lutaml/xml/schema/rnc_compiler_spec.rb'
51
+ - 'spec/lutaml/xml/schema/rng_compiler_spec.rb'
29
52
 
30
- # Offense count: 2
53
+ # Offense count: 25
31
54
  # This cop supports safe autocorrection (--autocorrect).
32
55
  Layout/BlockEndNewline:
33
56
  Exclude:
34
- - 'spec/lutaml/model/choice_restrict_spec.rb'
57
+ - 'lib/compat/opal/generate_boot.rb'
58
+ - 'lib/lutaml/model/schema/file_writer.rb'
59
+ - 'lib/lutaml/model/schema/renderers/mappings.rb'
60
+ - 'lib/lutaml/model/schema/renderers/member_decls.rb'
61
+ - 'lib/lutaml/model/schema/rnc_compiler.rb'
62
+ - 'lib/lutaml/model/schema/rng_compiler.rb'
63
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder.rb'
64
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb'
65
+ - 'lib/lutaml/model/union.rb'
66
+ - 'spec/lutaml/model/attribute_spec.rb'
67
+ - 'spec/lutaml/xml/schema/rnc_compiler_spec.rb'
68
+ - 'spec/lutaml/xml/schema/rng_compiler_spec.rb'
35
69
 
36
- # Offense count: 2
70
+ # Offense count: 6
37
71
  # This cop supports safe autocorrection (--autocorrect).
38
- # Configuration parameters: EnforcedStyle, IndentationWidth.
39
- # SupportedStyles: special_inside_parentheses, consistent, align_brackets
40
- Layout/FirstArrayElementIndentation:
72
+ # Configuration parameters: EmptyLineBetweenMethodDefs, EmptyLineBetweenClassDefs, EmptyLineBetweenModuleDefs, DefLikeMacros, AllowAdjacentOneLineDefs, NumberOfEmptyLines.
73
+ Layout/EmptyLineBetweenDefs:
41
74
  Exclude:
42
- - 'spec/lutaml/model/choice_restrict_spec.rb'
75
+ - 'lib/lutaml/model/schema/renderers/model.rb'
76
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder.rb'
43
77
 
44
- # Offense count: 4
78
+ # Offense count: 3
79
+ # This cop supports safe autocorrection (--autocorrect).
80
+ # Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment.
81
+ Layout/ExtraSpacing:
82
+ Exclude:
83
+ - 'lib/lutaml/model/schema/rng_compiler.rb'
84
+ - 'lib/lutaml/model/schema/xml_compiler.rb'
85
+
86
+ # Offense count: 33
87
+ # This cop supports safe autocorrection (--autocorrect).
88
+ # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
89
+ # SupportedHashRocketStyles: key, separator, table
90
+ # SupportedColonStyles: key, separator, table
91
+ # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
92
+ Layout/HashAlignment:
93
+ Exclude:
94
+ - 'lib/lutaml/model/schema/rnc_compiler/source_resolver.rb'
95
+ - 'lib/lutaml/model/schema/rng_compiler.rb'
96
+ - 'lib/lutaml/model/schema/rng_compiler/element_visitor.rb'
97
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder/complex_types.rb'
98
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb'
99
+ - 'spec/lutaml/model/union_attribute_spec.rb'
100
+
101
+ # Offense count: 50
45
102
  # This cop supports safe autocorrection (--autocorrect).
46
103
  # Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
47
104
  # SupportedStylesAlignWith: start_of_line, relative_to_receiver
48
105
  Layout/IndentationWidth:
49
106
  Exclude:
50
- - 'spec/lutaml/model/choice_restrict_spec.rb'
51
-
52
- # Offense count: 3071
107
+ - 'lib/compat/opal/generate_boot.rb'
108
+ - 'lib/lutaml/model/schema/file_writer.rb'
109
+ - 'lib/lutaml/model/schema/renderers/mappings.rb'
110
+ - 'lib/lutaml/model/schema/renderers/member_decls.rb'
111
+ - 'lib/lutaml/model/schema/rnc_compiler.rb'
112
+ - 'lib/lutaml/model/schema/rng_compiler.rb'
113
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder.rb'
114
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb'
115
+ - 'lib/lutaml/model/union.rb'
116
+ - 'spec/lutaml/model/attribute_spec.rb'
117
+ - 'spec/lutaml/xml/schema/rnc_compiler_spec.rb'
118
+ - 'spec/lutaml/xml/schema/rng_compiler_spec.rb'
119
+
120
+ # Offense count: 3250
53
121
  # This cop supports safe autocorrection (--autocorrect).
54
122
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
55
123
  # URISchemes: http, https
56
124
  Layout/LineLength:
57
125
  Enabled: false
58
126
 
59
- # Offense count: 1
60
- # This cop supports safe autocorrection (--autocorrect).
61
- # Configuration parameters: EnforcedStyle.
62
- # SupportedStyles: symmetrical, new_line, same_line
63
- Layout/MultilineArrayBraceLayout:
64
- Exclude:
65
- - 'spec/lutaml/model/choice_restrict_spec.rb'
66
-
67
- # Offense count: 1
127
+ # Offense count: 89
68
128
  # This cop supports safe autocorrection (--autocorrect).
69
129
  # Configuration parameters: AllowInHeredoc.
70
130
  Layout/TrailingWhitespace:
71
- Exclude:
72
- - 'lib/lutaml/rdf/linked_data_transform.rb'
131
+ Enabled: false
73
132
 
74
133
  # Offense count: 21
75
134
  # Configuration parameters: AllowedMethods.
@@ -82,12 +141,14 @@ Lint/ConstantDefinitionInBlock:
82
141
  - 'spec/lutaml/xml/type_namespace_prefix_spec.rb'
83
142
  - 'spec/lutaml/xml/xml_space_type_spec.rb'
84
143
 
85
- # Offense count: 35
144
+ # Offense count: 37
86
145
  # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
87
146
  Lint/DuplicateBranch:
88
147
  Enabled: false
89
148
 
90
149
  # Offense count: 3
150
+ # Configuration parameters: DelegatingMethods, AllowedCrossFilePaths.
151
+ # DelegatingMethods: delegate
91
152
  Lint/DuplicateMethods:
92
153
  Exclude:
93
154
  - 'lib/lutaml/xml/mapping.rb'
@@ -133,11 +194,6 @@ Lint/ReturnInVoidContext:
133
194
  Exclude:
134
195
  - 'lib/lutaml/model/serialize/builder.rb'
135
196
 
136
- # Offense count: 1
137
- Lint/ShadowedException:
138
- Exclude:
139
- - 'lib/lutaml/model/schema/xml_compiler/xml_namespace_class.rb'
140
-
141
197
  # Offense count: 1
142
198
  Lint/StructNewOverride:
143
199
  Exclude:
@@ -161,12 +217,12 @@ Lint/UselessConstantScoping:
161
217
  Exclude:
162
218
  - 'lib/lutaml/xml/mapping_rule.rb'
163
219
 
164
- # Offense count: 346
220
+ # Offense count: 357
165
221
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
166
222
  Metrics/AbcSize:
167
223
  Enabled: false
168
224
 
169
- # Offense count: 40
225
+ # Offense count: 42
170
226
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
171
227
  # AllowedMethods: refine
172
228
  Metrics/BlockLength:
@@ -177,23 +233,23 @@ Metrics/BlockLength:
177
233
  Metrics/BlockNesting:
178
234
  Max: 6
179
235
 
180
- # Offense count: 307
236
+ # Offense count: 319
181
237
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
182
238
  Metrics/CyclomaticComplexity:
183
239
  Enabled: false
184
240
 
185
- # Offense count: 554
241
+ # Offense count: 584
186
242
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
187
243
  Metrics/MethodLength:
188
244
  Max: 514
189
245
 
190
- # Offense count: 81
246
+ # Offense count: 89
191
247
  # Configuration parameters: CountKeywordArgs.
192
248
  Metrics/ParameterLists:
193
249
  MaxOptionalParameters: 5
194
250
  Max: 25
195
251
 
196
- # Offense count: 261
252
+ # Offense count: 268
197
253
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
198
254
  Metrics/PerceivedComplexity:
199
255
  Enabled: false
@@ -215,7 +271,7 @@ Naming/MethodParameterName:
215
271
  - 'lib/lutaml/model/type_context.rb'
216
272
  - 'lib/lutaml/xml/namespace.rb'
217
273
 
218
- # Offense count: 11
274
+ # Offense count: 10
219
275
  # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
220
276
  # AllowedMethods: call
221
277
  # WaywardPredicates: infinite?, nonzero?
@@ -223,7 +279,6 @@ Naming/PredicateMethod:
223
279
  Exclude:
224
280
  - 'lib/lutaml/model/attribute.rb'
225
281
  - 'lib/lutaml/model/mapping/mapping_rule.rb'
226
- - 'lib/lutaml/model/schema/xml_compiler/complex_type.rb'
227
282
  - 'lib/lutaml/xml/model_transform.rb'
228
283
  - 'lib/lutaml/xml/namespace_needs.rb'
229
284
  - 'lib/lutaml/xml/namespace_resolution_strategy.rb'
@@ -279,13 +334,13 @@ RSpec/BeforeAfterAll:
279
334
  - 'spec/lutaml/xml/fpi_namespace_spec.rb'
280
335
  - 'spec/lutaml/xml/namespace_spec.rb'
281
336
 
282
- # Offense count: 100
337
+ # Offense count: 113
283
338
  # Configuration parameters: Prefixes, AllowedPatterns.
284
339
  # Prefixes: when, with, without
285
340
  RSpec/ContextWording:
286
341
  Enabled: false
287
342
 
288
- # Offense count: 102
343
+ # Offense count: 107
289
344
  # Configuration parameters: IgnoredMetadata.
290
345
  RSpec/DescribeClass:
291
346
  Enabled: false
@@ -296,7 +351,7 @@ RSpec/DescribeMethod:
296
351
  - 'spec/lutaml/xml/schema/xsd/schema_helper_methods_spec.rb'
297
352
  - 'spec/lutaml/xml/serializable_namespace_spec.rb'
298
353
 
299
- # Offense count: 1343
354
+ # Offense count: 1428
300
355
  # Configuration parameters: CountAsOne.
301
356
  RSpec/ExampleLength:
302
357
  Max: 68
@@ -361,9 +416,10 @@ RSpec/MessageSpies:
361
416
  Exclude:
362
417
  - 'spec/lutaml/key_value/transformation/rule_compiler_spec.rb'
363
418
 
364
- # Offense count: 6
419
+ # Offense count: 7
365
420
  RSpec/MultipleDescribes:
366
421
  Exclude:
422
+ - 'spec/lutaml/model/defaults_spec.rb'
367
423
  - 'spec/lutaml/model/namespace_versioning_spec.rb'
368
424
  - 'spec/lutaml/model/transformation_builder_spec.rb'
369
425
  - 'spec/lutaml/xml/compiled_rule_namespace_spec.rb'
@@ -371,11 +427,11 @@ RSpec/MultipleDescribes:
371
427
  - 'spec/lutaml/xml/namespace_resolution_strategy_spec.rb'
372
428
  - 'spec/lutaml/xml/xml_space_type_spec.rb'
373
429
 
374
- # Offense count: 1576
430
+ # Offense count: 1668
375
431
  RSpec/MultipleExpectations:
376
432
  Max: 21
377
433
 
378
- # Offense count: 190
434
+ # Offense count: 198
379
435
  # Configuration parameters: AllowSubject.
380
436
  RSpec/MultipleMemoizedHelpers:
381
437
  Max: 15
@@ -419,7 +475,7 @@ RSpec/RepeatedExampleGroupDescription:
419
475
  Exclude:
420
476
  - 'spec/lutaml/model/mixed_content_spec.rb'
421
477
 
422
- # Offense count: 39
478
+ # Offense count: 31
423
479
  # Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
424
480
  # SupportedInflectors: default, active_support
425
481
  RSpec/SpecFilePathFormat:
@@ -445,7 +501,7 @@ Security/MarshalLoad:
445
501
  Exclude:
446
502
  - 'scripts-xmi-profile/profile_xmi.rb'
447
503
 
448
- # Offense count: 3
504
+ # Offense count: 38
449
505
  # This cop supports safe autocorrection (--autocorrect).
450
506
  # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
451
507
  # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
@@ -454,7 +510,18 @@ Security/MarshalLoad:
454
510
  # AllowedMethods: lambda, proc, it
455
511
  Style/BlockDelimiters:
456
512
  Exclude:
457
- - 'spec/lutaml/model/choice_restrict_spec.rb'
513
+ - 'lib/compat/opal/generate_boot.rb'
514
+ - 'lib/lutaml/model/schema/file_writer.rb'
515
+ - 'lib/lutaml/model/schema/renderers/mappings.rb'
516
+ - 'lib/lutaml/model/schema/renderers/member_decls.rb'
517
+ - 'lib/lutaml/model/schema/rnc_compiler.rb'
518
+ - 'lib/lutaml/model/schema/rng_compiler.rb'
519
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder.rb'
520
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb'
521
+ - 'lib/lutaml/model/union.rb'
522
+ - 'spec/lutaml/model/attribute_spec.rb'
523
+ - 'spec/lutaml/xml/schema/rnc_compiler_spec.rb'
524
+ - 'spec/lutaml/xml/schema/rng_compiler_spec.rb'
458
525
 
459
526
  # Offense count: 2
460
527
  # This cop supports unsafe autocorrection (--autocorrect-all).
@@ -501,6 +568,17 @@ Style/MixinUsage:
501
568
  - 'bench/bench_unitsml.rb'
502
569
  - 'bench/bench_xmi.rb'
503
570
 
571
+ # Offense count: 19
572
+ # This cop supports safe autocorrection (--autocorrect).
573
+ Style/MultilineIfModifier:
574
+ Exclude:
575
+ - 'lib/lutaml/model/attribute.rb'
576
+ - 'lib/lutaml/model/schema/rnc_compiler/source_resolver.rb'
577
+ - 'lib/lutaml/model/schema/rng_compiler/element_visitor.rb'
578
+ - 'lib/lutaml/model/schema/xml_compiler.rb'
579
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder.rb'
580
+ - 'lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb'
581
+
504
582
  # Offense count: 12
505
583
  # Configuration parameters: AllowedClasses.
506
584
  Style/OneClassPerFile:
@@ -539,20 +617,3 @@ Style/SafeNavigation:
539
617
  Style/SafeNavigationChainLength:
540
618
  Exclude:
541
619
  - 'lib/lutaml/xml/mapping.rb'
542
-
543
- # Offense count: 3
544
- # This cop supports unsafe autocorrection (--autocorrect-all).
545
- # Configuration parameters: Mode.
546
- Style/StringConcatenation:
547
- Exclude:
548
- - 'lib/lutaml/model/schema/xml_compiler/complex_type.rb'
549
- - 'lib/lutaml/model/schema/xml_compiler/simple_type.rb'
550
- - 'lib/lutaml/model/schema/xml_compiler/xml_namespace_class.rb'
551
-
552
- # Offense count: 1
553
- # child_names_set may be a Set; Array#intersect? requires an Array, so
554
- # the autocorrect from rubocop 1.88.2's Style/ArrayIntersect would
555
- # break runtime. Use the block form.
556
- Style/ArrayIntersect:
557
- Exclude:
558
- - 'lib/lutaml/xml/model_transform.rb'
@@ -22,23 +22,26 @@ module BenchCommon
22
22
  module_function
23
23
 
24
24
  # Measure parse time and allocations for a block
25
- def measure(name, iterations: ITERATIONS, &)
25
+ def measure(name, iterations: ITERATIONS, &block)
26
26
  # Warmup
27
- WARMUP_ITERATIONS.times(&)
27
+ WARMUP_ITERATIONS.times(&block)
28
28
 
29
29
  times = []
30
30
  allocations = []
31
31
  iterations.times do
32
32
  GC.start
33
33
  GC.disable
34
- mem_before = ObjectSpace.count_objects[:TOTAL]
34
+ # Must be a monotonic counter: count_objects[:TOTAL] counts occupied
35
+ # slots, so allocations that reuse slots freed by the GC.start above
36
+ # are invisible (observed as 0-alloc parses and unstable ratios).
37
+ alloc_before = GC.stat(:total_allocated_objects)
35
38
  t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
36
39
  yield
37
40
  t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
38
41
  GC.enable
39
- mem_after = ObjectSpace.count_objects[:TOTAL]
42
+ alloc_after = GC.stat(:total_allocated_objects)
40
43
  times << (t1 - t0)
41
- allocations << (mem_after - mem_before)
44
+ allocations << (alloc_after - alloc_before)
42
45
  end
43
46
 
44
47
  avg_time = times.sum / times.size
data/bench/bench_niso.rb CHANGED
@@ -11,8 +11,7 @@
11
11
  # NOTE: Must run from the niso-jats bundle:
12
12
  # cd $NISO_DIR && bundle exec ruby /path/to/lutaml-model/bench/bench_niso.rb
13
13
 
14
- lutaml_model_root = ENV["LUTAML_MODEL_DIR"] || "/Users/mulgogi/src/lutaml/lutaml-model"
15
- require "#{lutaml_model_root}/bench/bench_common"
14
+ require_relative "bench_common"
16
15
  include BenchCommon
17
16
 
18
17
  print_header("NISO JATS Benchmark — Journal Article parsing")
data/bench/gate_config.rb CHANGED
@@ -57,7 +57,10 @@ module GateConfig
57
57
  "iso-13849-1MB" => {
58
58
  alloc_ratio: 1.05,
59
59
  time_ratio: 1.15,
60
- absolute_max: 5.0,
60
+ # GH-hosted ubuntu runners run this fixture at ~12s min_time
61
+ # (observed across moxml 0.1–0.5); 5.0 never passed there and
62
+ # fired on every run. 15.0 keeps the 2x-catastrophe safety net.
63
+ absolute_max: 15.0,
61
64
  },
62
65
  "din-iso-1.1MB" => {
63
66
  alloc_ratio: 1.05,
@@ -394,7 +394,7 @@ class BenchmarkRunner
394
394
  @results[name]
395
395
  end
396
396
 
397
- def run_memory_benchmark(&)
397
+ def run_memory_benchmark(&block)
398
398
  # Force GC before measurement
399
399
  GC.start
400
400
  GC.compact if GC.respond_to?(:compact)
@@ -403,7 +403,7 @@ class BenchmarkRunner
403
403
  profile = RubyProf::Profile.new(measure_mode: RubyProf::ALLOCATIONS)
404
404
 
405
405
  profile.start
406
- 10.times(&)
406
+ 10.times(&block)
407
407
  result = profile.stop
408
408
 
409
409
  # Print allocation report
@@ -418,12 +418,12 @@ class BenchmarkRunner
418
418
  puts " Memory profiling skipped: #{e.message}"
419
419
  end
420
420
 
421
- def run_cpu_profile(name, &)
421
+ def run_cpu_profile(name, &block)
422
422
  # ruby-prof 2.0 API: create a profile with wall time measurement
423
423
  profile = RubyProf::Profile.new(measure_mode: RubyProf::WALL_TIME)
424
424
 
425
425
  profile.start
426
- ITERATIONS.times(&)
426
+ ITERATIONS.times(&block)
427
427
  result = profile.stop
428
428
 
429
429
  # Print flat report to console
@@ -0,0 +1,127 @@
1
+ ---
2
+ title: Builder DSL
3
+ nav_order: 99
4
+ ---
5
+
6
+ = Builder DSL
7
+ :toc:
8
+ :toclevels: 3
9
+
10
+ The Builder DSL gives any `Lutaml::Model::Serializable` class a block-based
11
+ construction syntax:
12
+
13
+ [source,ruby]
14
+ ----
15
+ person = Person.new do |p|
16
+ p.name "Ada"
17
+ p.email "ada@example.com"
18
+ end
19
+ ----
20
+
21
+ It works for every model. For models declared with `ordered` or
22
+ `mixed_content`, the builder also records the order in which attributes were
23
+ mutated so that `to_xml` can emit child elements in the same order.
24
+
25
+ == Two equivalent syntaxes
26
+
27
+ Every attribute supports both the *appender* form and the *direct setter* form
28
+ inside the block. They are interchangeable:
29
+
30
+ [source,ruby]
31
+ ----
32
+ # Appender form: looks like a method call with the value as argument
33
+ person = Person.new do |p|
34
+ p.name "Ada" # equivalent to p.name = "Ada"
35
+ p.email "ada@x.org" # equivalent to p.email = "ada@x.org"
36
+ end
37
+
38
+ # Direct setter form: looks like a normal assignment
39
+ person = Person.new do |p|
40
+ p.name = "Ada"
41
+ p.email = "ada@x.org"
42
+ end
43
+ ----
44
+
45
+ Both snippets produce identical `to_xml`, `to_json`, etc. Use whichever reads
46
+ better in context.
47
+
48
+ === Collections
49
+
50
+ Collection attributes accept both forms too:
51
+
52
+ [source,ruby]
53
+ ----
54
+ group = Group.new do |g|
55
+ # Append one item at a time:
56
+ g.member(person1)
57
+ g.member(person2)
58
+
59
+ # Or assign the whole collection at once:
60
+ g.members = [person1, person2, person3]
61
+ end
62
+ ----
63
+
64
+ The wholesale assignment records one order-entry per item, so the resulting
65
+ `element_order` length matches the number of serialized child elements.
66
+
67
+ == Order tracking and serialization
68
+
69
+ The builder tracks call order only when *all* of the following are true:
70
+
71
+ 1. The instance was constructed via `Klass.new do |x| ... end` (a block was
72
+ passed).
73
+ 2. The XML mapping is declared with `ordered` or `mixed_content`.
74
+
75
+ When tracking is active, every mutation (via either syntax) is appended to the
76
+ instance's `element_order`. `to_xml` then iterates `element_order` to emit
77
+ child elements in the order they were set.
78
+
79
+ When tracking is *not* active (no block, or the model is neither `ordered` nor
80
+ `mixed_content`), `element_order` stays `nil` and `to_xml` emits elements in
81
+ declaration order.
82
+
83
+ === Equivalence with `.tap`
84
+
85
+ The block form is the only way to enable tracking. Constructing the instance
86
+ separately and mutating it afterwards does not enable tracking:
87
+
88
+ [source,ruby]
89
+ ----
90
+ # Tracking active:
91
+ item = Item.new { |i| i.b = "first"; i.a = "second" }
92
+ item.element_order.map(&:name) # => ["b", "a"]
93
+
94
+ # Tracking NOT active:
95
+ item = Item.new
96
+ item.b = "first"
97
+ item.a = "second"
98
+ item.element_order # => nil
99
+ # Falls back to declaration order for serialization.
100
+ ----
101
+
102
+ If you want call-order preservation, use the block form.
103
+
104
+ == No silent data loss (invariant)
105
+
106
+ The serializer guarantees that every attribute with a non-default value appears
107
+ in the serialized output, regardless of which syntax was used to set it.
108
+
109
+ This is enforced by `OrderedApplier#apply_remaining_rules`: any element-typed
110
+ attribute not represented in `element_order` is emitted in declaration order
111
+ after the tracked entries. This is a safety net on top of the builder's own
112
+ tracking, so that future code paths (new mutation helpers, attribute merge
113
+ operations, etc.) cannot silently drop user data.
114
+
115
+ If you find an attribute missing from `to_xml`, the right answer is to fix the
116
+ mutation path so it records into `element_order`. The safety net guarantees
117
+ correctness; it does not guarantee order.
118
+
119
+ == Performance notes
120
+
121
+ For models that are neither `ordered` nor `mixed_content`, the builder does
122
+ not allocate any `Lutaml::Xml::Element` order-tracking objects. The check is
123
+ `@__order_tracking__` (a boolean), and the recording helpers are no-ops.
124
+
125
+ The check is also a no-op for `ordered`/`mixed_content` models constructed
126
+ without a block. This keeps the common case (`Klass.from_xml(xml)` followed
127
+ by `to_xml`) free of tracking overhead.
@@ -194,6 +194,33 @@ Use Custom Value Type classes when:
194
194
  * **Testable** - Easy to unit test in isolation
195
195
  * **Maintainable** - Centralized logic, easier to modify
196
196
 
197
+ ==== Whole-Value Types (Scalar or List)
198
+
199
+ A custom value type on a non-collection attribute receives the raw value
200
+ whole — including Arrays — so a type may legitimately wrap a scalar *or* a
201
+ list in a single slot:
202
+
203
+ [source,ruby]
204
+ ----
205
+ class LiteralValue < Lutaml::Model::Type::Value
206
+ end
207
+
208
+ class LiteralDoc < Lutaml::Model::Serializable
209
+ attribute :v, LiteralValue
210
+ key_value do
211
+ map "v", to: :v
212
+ end
213
+ end
214
+
215
+ LiteralDoc.from_yaml("v: hello").v # => "hello"
216
+ LiteralDoc.from_yaml("v: [a, b]").v # => ["a", "b"]
217
+ ----
218
+
219
+ Built-in scalar types keep the guidance error: an Array arriving on a
220
+ non-collection attribute of a built-in type still raises
221
+ `CollectionTrueMissingError` ("May be `collection: true` is missing").
222
+ Declare `collection: true` for list attributes.
223
+
197
224
  ==== Complete Example: Bidirectional Date Formats
198
225
 
199
226
  [source,ruby]