lutaml-model 0.8.18 → 0.9.1

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.

Potentially problematic release.


This version of lutaml-model might be problematic. Click here for more details.

Files changed (59) 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_todo.yml +133 -72
  5. data/bench/bench_common.rb +6 -3
  6. data/bench/bench_niso.rb +1 -2
  7. data/docs/_guides/builder-dsl.adoc +127 -0
  8. data/lib/compat/opal/generate_boot.rb +3 -1
  9. data/lib/lutaml/key_value/transform.rb +4 -1
  10. data/lib/lutaml/key_value/transformation/value_serializer.rb +0 -2
  11. data/lib/lutaml/model/attribute.rb +23 -2
  12. data/lib/lutaml/model/global_context.rb +4 -2
  13. data/lib/lutaml/model/schema/class_loader.rb +2 -1
  14. data/lib/lutaml/model/schema/definitions/namespace.rb +2 -1
  15. data/lib/lutaml/model/schema/file_writer.rb +5 -2
  16. data/lib/lutaml/model/schema/renderers/base.rb +2 -1
  17. data/lib/lutaml/model/schema/renderers/mappings.rb +9 -3
  18. data/lib/lutaml/model/schema/renderers/member_decls.rb +9 -3
  19. data/lib/lutaml/model/schema/renderers/model.rb +16 -4
  20. data/lib/lutaml/model/schema/renderers/required_files_calculator.rb +2 -1
  21. data/lib/lutaml/model/schema/renderers.rb +2 -1
  22. data/lib/lutaml/model/schema/rnc_compiler/source_resolver.rb +6 -2
  23. data/lib/lutaml/model/schema/rnc_compiler.rb +3 -1
  24. data/lib/lutaml/model/schema/rng_compiler/element_visitor.rb +35 -15
  25. data/lib/lutaml/model/schema/rng_compiler/value_type_resolver.rb +4 -2
  26. data/lib/lutaml/model/schema/rng_compiler.rb +10 -5
  27. data/lib/lutaml/model/schema/xml_compiler/element_order.rb +2 -1
  28. data/lib/lutaml/model/schema/xml_compiler/spec_builder/complex_types.rb +4 -2
  29. data/lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb +39 -13
  30. data/lib/lutaml/model/schema/xml_compiler/spec_builder.rb +29 -10
  31. data/lib/lutaml/model/schema/xml_compiler.rb +10 -5
  32. data/lib/lutaml/model/serialize/attribute_definition.rb +10 -9
  33. data/lib/lutaml/model/serialize/builder.rb +55 -0
  34. data/lib/lutaml/model/serialize/initialization.rb +12 -3
  35. data/lib/lutaml/model/serialize/model_import.rb +1 -0
  36. data/lib/lutaml/model/serialize.rb +5 -4
  37. data/lib/lutaml/model/union.rb +5 -2
  38. data/lib/lutaml/model/version.rb +1 -1
  39. data/lib/lutaml/xml/mapping_rule.rb +55 -1
  40. data/lib/lutaml/xml/model_transform.rb +53 -5
  41. data/lib/lutaml/xml/schema/xsd.rb +0 -2
  42. data/lib/lutaml/xml/schema/xsd_schema.rb +2 -1
  43. data/lib/lutaml/xml/transformation/element_builder.rb +2 -1
  44. data/lib/lutaml/xml/transformation/ordered_applier.rb +99 -4
  45. data/lutaml-model.gemspec +4 -1
  46. data/spec/lutaml/model/attribute_apply_value_map_spec.rb +26 -13
  47. data/spec/lutaml/model/attribute_spec.rb +8 -3
  48. data/spec/lutaml/model/custom_from_empty_values_spec.rb +74 -0
  49. data/spec/lutaml/model/defaults_spec.rb +45 -0
  50. data/spec/lutaml/model/json_spec.rb +1 -2
  51. data/spec/lutaml/model/ordered_content_spec.rb +18 -7
  52. data/spec/lutaml/model/serialize/builder_spec.rb +361 -0
  53. data/spec/lutaml/model/transform_apply_value_map_spec.rb +6 -3
  54. data/spec/lutaml/model/union_attribute_spec.rb +4 -2
  55. data/spec/lutaml/xml/attribute_namespace_disjointness_spec.rb +125 -0
  56. data/spec/lutaml/xml/schema/rnc_compiler_spec.rb +17 -6
  57. data/spec/lutaml/xml/schema/rng_compiler_spec.rb +15 -6
  58. data/spec/lutaml/xml/w3c_types_spec.rb +3 -6
  59. metadata +7 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 852a93ce391ef7eb0f8e7673bda66f7bb417637b252735cebe833d1e305a6c7b
4
- data.tar.gz: 65f067c3e0bf4e1d520d5e2d133a6de4606900844b5e91d367ce4edee51da0e1
3
+ metadata.gz: e2ed11dbd5362f84417977f49692e75c564e9834077cbd4ccde02105c5da7f3f
4
+ data.tar.gz: 99a8bd473ab609e61a21954aff2b2506ab2bd66bdba10a8094473fdc57570fb8
5
5
  SHA512:
6
- metadata.gz: 318f15b16d919319fd4c2cd9c2722a1ee37b8f1a4272b5a966ce45bf2811447c7c1004642fd76c3204ddd70c8fb4ac6de9397e67f7305529e4b2310769fca52b
7
- data.tar.gz: 65479ec0a4e9ef58938953f94802da282bfe2d443c4d7cd41a9bf83973e653c3d6ce700fb9eb07e7e5cf1ffa120cfb54fded8d71d8215f4e35c76360dd6393fe
6
+ metadata.gz: 9ae49b37edd0a3e5dbc5ab6176e736aa6f88db8c8f11b573b728336e01aa8fa8860f69ee9cf0f3371028bb5f334bb9d09a59a583aafc3ec12499cbaf5f73b9d1
7
+ data.tar.gz: fe32b41bba66da58f41922d7ab5ebd400ac5cd68b8dc8cdb8673a41f81890e73753908df125687d3450ca602c6a0b7bae23130c9987892798a132e1a8b9d8988
@@ -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_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'
@@ -31,14 +31,17 @@ module BenchCommon
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")
@@ -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.
@@ -38,7 +38,9 @@ DECL_RE = /autoload\s+:[A-Za-z0-9_]+\s*,\s*"([^"]+)"/
38
38
  # DECL_RE can match. We only merge when the line ends right after the
39
39
  # comma that follows `autoload :Name`.
40
40
  def join_multiline_autoloads(src)
41
- src.gsub(/(autoload\s+:[A-Za-z0-9_]+\s*,)\s*\n\s*/) { "#{Regexp.last_match(1)} " }
41
+ src.gsub(/(autoload\s+:[A-Za-z0-9_]+\s*,)\s*\n\s*/) do
42
+ "#{Regexp.last_match(1)} "
43
+ end
42
44
  end
43
45
 
44
46
  # Resolve an autoload's raw string argument to a require path relative to
@@ -249,7 +249,10 @@ format)
249
249
  value = apply_value_map(value, rule.value_map(:from, options), attr)
250
250
 
251
251
  if rule.has_custom_method_for_deserialization?
252
- return unless Lutaml::Model::Utils.present?(value)
252
+ # An empty value ("", [], {}) is a present value per the
253
+ # missing-values semantics and must reach the custom method;
254
+ # only nil (non-existent) skips it (lutaml-model#746).
255
+ return if value.nil?
253
256
 
254
257
  return rule.deserialize(instance, value, attributes, model_class)
255
258
  end
@@ -88,11 +88,9 @@ model_class: nil)
88
88
  # @param rule [CompiledRule] The compiled rule
89
89
  # @return [Boolean] true if the rule defines a nested model
90
90
  def nested_model?(rule)
91
- # rubocop:disable Style/IncludeOrExtend
92
91
  # Use include? instead of < because < returns nil (not false) for non-subclasses
93
92
  rule.attribute_type.is_a?(Class) &&
94
93
  rule.attribute_type.include?(Lutaml::Model::Serialize)
95
- # rubocop:enable Style/IncludeOrExtend
96
94
  end
97
95
 
98
96
  # Serialize a nested model to a hash representation.
@@ -394,7 +394,9 @@ instance_object = nil)
394
394
  instance_object)
395
395
  elsif options[:default].is_a?(Proc)
396
396
  if instance_object
397
- instance_object.instance_exec(&options[:default])
397
+ ::Lutaml::Model::Attribute.evaluating_default do
398
+ instance_object.instance_exec(&options[:default])
399
+ end
398
400
  else
399
401
  options[:default].call
400
402
  end
@@ -405,6 +407,22 @@ instance_object = nil)
405
407
  end
406
408
  end
407
409
 
410
+ # Marks the dynamic extent in which a default proc runs against a
411
+ # model instance, so Serialize#method_missing can fall back to the
412
+ # model class for methods the instance does not define (0.7.x
413
+ # compatibility, lutaml-model#745).
414
+ def self.evaluating_default
415
+ previous = Thread.current[:__lutaml_evaluating_default]
416
+ Thread.current[:__lutaml_evaluating_default] = true
417
+ yield
418
+ ensure
419
+ Thread.current[:__lutaml_evaluating_default] = previous
420
+ end
421
+
422
+ def self.default_evaluation?
423
+ Thread.current[:__lutaml_evaluating_default] == true
424
+ end
425
+
408
426
  def default_set?(register, instance_object = nil)
409
427
  !Utils.uninitialized?(default_value(register, instance_object))
410
428
  end
@@ -478,7 +496,10 @@ instance_object = nil)
478
496
  # Use the default value if the value is nil
479
497
  validate_required!(value)
480
498
 
481
- value = cast_value(default_value(register, instance_object), register) if value.nil?
499
+ if value.nil?
500
+ value = cast_value(default_value(register, instance_object),
501
+ register)
502
+ end
482
503
  resolved_type = type(register)
483
504
 
484
505
  valid_value!(value) &&
@@ -436,8 +436,10 @@ context_id = nil)
436
436
  instance.register_for_namespace(namespace_uri)
437
437
  end
438
438
 
439
- def resolve_type_with_namespace(type_name, namespace_uri = nil, context_id = nil)
440
- instance.resolve_type_with_namespace(type_name, namespace_uri, context_id)
439
+ def resolve_type_with_namespace(type_name, namespace_uri = nil,
440
+ context_id = nil)
441
+ instance.resolve_type_with_namespace(type_name, namespace_uri,
442
+ context_id)
441
443
  end
442
444
 
443
445
  def namespace_register_map