lutaml-model 0.8.19 → 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 (120) 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/value-transformations.adoc +27 -0
  11. data/lib/compat/opal/generate_boot.rb +3 -1
  12. data/lib/compat/opal/lutaml_model_boot.rb +10 -7
  13. data/lib/compat/opal/moxml_boot.rb +6 -1
  14. data/lib/lutaml/hash_format/format.rb +29 -0
  15. data/lib/lutaml/hash_format.rb +5 -27
  16. data/lib/lutaml/json/format.rb +61 -0
  17. data/lib/lutaml/json.rb +4 -59
  18. data/lib/lutaml/jsonl/format.rb +22 -0
  19. data/lib/lutaml/jsonl.rb +5 -19
  20. data/lib/lutaml/key_value/format.rb +26 -0
  21. data/lib/lutaml/key_value/transform.rb +4 -1
  22. data/lib/lutaml/key_value/transformation/value_serializer.rb +0 -2
  23. data/lib/lutaml/key_value.rb +4 -21
  24. data/lib/lutaml/model/attribute.rb +38 -4
  25. data/lib/lutaml/model/collection.rb +2 -2
  26. data/lib/lutaml/model/compiled_rule.rb +1 -1
  27. data/lib/lutaml/model/config.rb +2 -2
  28. data/lib/lutaml/model/consolidation_map.rb +2 -2
  29. data/lib/lutaml/model/consolidation_rule/dispatch_block.rb +2 -2
  30. data/lib/lutaml/model/errors.rb +2 -2
  31. data/lib/lutaml/model/global_context.rb +4 -2
  32. data/lib/lutaml/model/mapping/mapping_rule.rb +4 -1
  33. data/lib/lutaml/model/mapping/model_mapping.rb +2 -2
  34. data/lib/lutaml/model/runtime_compatibility.rb +2 -2
  35. data/lib/lutaml/model/schema/class_loader.rb +2 -1
  36. data/lib/lutaml/model/schema/decorators/definition_collection.rb +4 -4
  37. data/lib/lutaml/model/schema/definitions/namespace.rb +2 -1
  38. data/lib/lutaml/model/schema/file_writer.rb +5 -2
  39. data/lib/lutaml/model/schema/renderers/base.rb +4 -3
  40. data/lib/lutaml/model/schema/renderers/mappings.rb +9 -3
  41. data/lib/lutaml/model/schema/renderers/member_decls.rb +9 -3
  42. data/lib/lutaml/model/schema/renderers/model.rb +18 -6
  43. data/lib/lutaml/model/schema/renderers/required_files_calculator.rb +2 -1
  44. data/lib/lutaml/model/schema/renderers.rb +2 -1
  45. data/lib/lutaml/model/schema/rnc_compiler/source_resolver.rb +6 -2
  46. data/lib/lutaml/model/schema/rnc_compiler.rb +3 -1
  47. data/lib/lutaml/model/schema/rng_compiler/element_visitor.rb +35 -15
  48. data/lib/lutaml/model/schema/rng_compiler/value_type_resolver.rb +4 -2
  49. data/lib/lutaml/model/schema/rng_compiler.rb +10 -5
  50. data/lib/lutaml/model/schema/xml_compiler/element_order.rb +2 -1
  51. data/lib/lutaml/model/schema/xml_compiler/spec_builder/complex_types.rb +4 -2
  52. data/lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb +39 -13
  53. data/lib/lutaml/model/schema/xml_compiler/spec_builder.rb +29 -10
  54. data/lib/lutaml/model/schema/xml_compiler/supported_data_types.rb +2 -2
  55. data/lib/lutaml/model/schema/xml_compiler.rb +10 -5
  56. data/lib/lutaml/model/sequence.rb +4 -4
  57. data/lib/lutaml/model/serialize/attribute_definition.rb +1 -0
  58. data/lib/lutaml/model/serialize/format_conversion.rb +2 -2
  59. data/lib/lutaml/model/serialize/initialization.rb +9 -1
  60. data/lib/lutaml/model/serialize/model_import.rb +1 -0
  61. data/lib/lutaml/model/serialize.rb +4 -3
  62. data/lib/lutaml/model/type/uninitialized_class_guard.rb +1 -1
  63. data/lib/lutaml/model/type.rb +9 -0
  64. data/lib/lutaml/model/type_registry.rb +2 -2
  65. data/lib/lutaml/model/uninitialized_class.rb +1 -1
  66. data/lib/lutaml/model/union.rb +5 -2
  67. data/lib/lutaml/model/utils.rb +2 -2
  68. data/lib/lutaml/model/value_policy.rb +27 -0
  69. data/lib/lutaml/model/version.rb +1 -1
  70. data/lib/lutaml/model.rb +17 -16
  71. data/lib/lutaml/rdf/mapping.rb +2 -2
  72. data/lib/lutaml/rdf/namespace_set.rb +2 -2
  73. data/lib/lutaml/rdf/transform.rb +2 -2
  74. data/lib/lutaml/toml/format.rb +48 -0
  75. data/lib/lutaml/toml.rb +5 -46
  76. data/lib/lutaml/xml/adapter/base_adapter.rb +2 -2
  77. data/lib/lutaml/xml/builder/base.rb +2 -2
  78. data/lib/lutaml/xml/format.rb +331 -0
  79. data/lib/lutaml/xml/mapping.rb +2 -2
  80. data/lib/lutaml/xml/mapping_rule.rb +62 -3
  81. data/lib/lutaml/xml/model_transform.rb +132 -55
  82. data/lib/lutaml/xml/namespace_collector.rb +3 -3
  83. data/lib/lutaml/xml/parse_session.rb +59 -0
  84. data/lib/lutaml/xml/parsed_namespace_set.rb +2 -2
  85. data/lib/lutaml/xml/schema/builder.rb +5 -5
  86. data/lib/lutaml/xml/schema/xsd/schema_location_mapping.rb +2 -2
  87. data/lib/lutaml/xml/schema/xsd.rb +0 -2
  88. data/lib/lutaml/xml/schema/xsd_schema.rb +2 -1
  89. data/lib/lutaml/xml/serialization/format_conversion.rb +3 -3
  90. data/lib/lutaml/xml/transformation/element_builder.rb +2 -1
  91. data/lib/lutaml/xml/transformation/ordered_applier.rb +2 -1
  92. data/lib/lutaml/xml/xml_element.rb +2 -0
  93. data/lib/lutaml/xml.rb +4 -328
  94. data/lib/lutaml/yaml/format.rb +30 -0
  95. data/lib/lutaml/yaml.rb +5 -28
  96. data/lib/lutaml/yamls/adapter/mapping.rb +2 -2
  97. data/lib/lutaml/yamls/format.rb +22 -0
  98. data/lib/lutaml/yamls.rb +5 -19
  99. data/lib/tasks/benchmark_runner.rb +2 -2
  100. data/lutaml-model.gemspec +1 -1
  101. data/spec/lutaml/model/attribute_apply_value_map_spec.rb +26 -13
  102. data/spec/lutaml/model/attribute_spec.rb +8 -3
  103. data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +2 -2
  104. data/spec/lutaml/model/custom_from_empty_values_spec.rb +74 -0
  105. data/spec/lutaml/model/custom_vobject_adapter_spec.rb +8 -8
  106. data/spec/lutaml/model/defaults_spec.rb +45 -0
  107. data/spec/lutaml/model/json_spec.rb +1 -2
  108. data/spec/lutaml/model/serialize/builder_spec.rb +6 -3
  109. data/spec/lutaml/model/store_spec.rb +3 -1
  110. data/spec/lutaml/model/transform_apply_value_map_spec.rb +6 -3
  111. data/spec/lutaml/model/union_attribute_spec.rb +4 -2
  112. data/spec/lutaml/model/value_policy_spec.rb +82 -0
  113. data/spec/lutaml/require_load_order_spec.rb +25 -0
  114. data/spec/lutaml/xml/attribute_element_namespace_disjoint_spec.rb +88 -0
  115. data/spec/lutaml/xml/attribute_namespace_disjointness_spec.rb +125 -0
  116. data/spec/lutaml/xml/out_of_namespace_parsing_spec.rb +123 -0
  117. data/spec/lutaml/xml/schema/rnc_compiler_spec.rb +17 -6
  118. data/spec/lutaml/xml/schema/rng_compiler_spec.rb +15 -6
  119. data/spec/lutaml/xml/w3c_types_spec.rb +3 -6
  120. metadata +20 -4
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Internal Hash format implementation. Loaded from lib/lutaml/hash_format.rb
4
+ # (the public entrypoint) and from lib/lutaml/model.rb (so the model
5
+ # entrypoint triggers the registration side effects).
6
+ # No require_relative "model" here — keeps the require graph acyclic.
7
+
8
+ module Lutaml
9
+ module HashFormat
10
+ class Error < StandardError; end
11
+
12
+ autoload :Adapter, "#{__dir__}/adapter"
13
+ end
14
+ end
15
+
16
+ Lutaml::Model::FormatRegistry.register(
17
+ :hash,
18
+ mapping_class: Lutaml::HashFormat::Adapter::Mapping,
19
+ adapter_class: Lutaml::HashFormat::Adapter::StandardAdapter,
20
+ transformer: Lutaml::HashFormat::Adapter::Transform,
21
+ key_value: true,
22
+ adapter_options: {
23
+ available: %i[standard standard_hash],
24
+ default: :standard,
25
+ },
26
+ )
27
+
28
+ require_relative "type/serializers"
29
+ Lutaml::HashFormat::Type::Serializers.register_all!
@@ -1,29 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Hash format module
4
- # Provides Lutaml::HashFormat namespace for Hash serialization
5
-
6
- module Lutaml
7
- module HashFormat
8
- class Error < StandardError; end
9
-
10
- autoload :Adapter, "#{__dir__}/hash_format/adapter"
11
- end
12
- end
13
-
14
- # Register Hash format with the format registry
15
- Lutaml::Model::FormatRegistry.register(
16
- :hash,
17
- mapping_class: Lutaml::HashFormat::Adapter::Mapping,
18
- adapter_class: Lutaml::HashFormat::Adapter::StandardAdapter,
19
- transformer: Lutaml::HashFormat::Adapter::Transform,
20
- key_value: true,
21
- adapter_options: {
22
- available: %i[standard standard_hash],
23
- default: :standard,
24
- },
25
- )
26
-
27
- # Register Hash type serializers
28
- require_relative "hash_format/type/serializers"
29
- Lutaml::HashFormat::Type::Serializers.register_all!
3
+ # Public Hash format entrypoint. Loads the base model and the internal
4
+ # implementation. The internal file does not require the model back,
5
+ # which keeps the require graph acyclic.
6
+ require_relative "model"
7
+ require_relative "hash_format/format"
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Internal JSON format implementation. Loaded from lib/lutaml/json.rb
4
+ # (the public entrypoint) and from lib/lutaml/model.rb (so the model
5
+ # entrypoint triggers the registration side effects).
6
+ # No require_relative "model" here — keeps the require graph acyclic.
7
+
8
+ require "lutaml/model/runtime_compatibility"
9
+ require_relative "../key_value/format"
10
+
11
+ module Lutaml
12
+ module Json
13
+ class Error < StandardError; end
14
+
15
+ require_relative "adapter/document"
16
+ require_relative "adapter/mapping"
17
+ require_relative "adapter/mapping_rule"
18
+ require_relative "adapter/transform"
19
+ require_relative "adapter/standard_adapter"
20
+ Lutaml::Model::RuntimeCompatibility.require_native(
21
+ "#{__dir__}/adapter/oj_adapter",
22
+ "#{__dir__}/adapter/multi_json_adapter",
23
+ )
24
+ require_relative "schema"
25
+
26
+ # Convenience aliases for common classes at the module level
27
+ # Allows Lutaml::Json::Mapping to resolve to Lutaml::Json::Adapter::Mapping
28
+ def self.const_missing(name)
29
+ if Adapter.const_defined?(name, false)
30
+ Adapter.const_get(name, false)
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ # Detect available JSON adapters
37
+ def self.detect_adapter
38
+ return :standard if defined?(::JSON) && Lutaml::Model.opal?
39
+ return :oj if defined?(::Oj)
40
+ return :multi_json if defined?(::MultiJson)
41
+ return :standard if defined?(::JSON)
42
+
43
+ nil
44
+ end
45
+ end
46
+ end
47
+
48
+ Lutaml::Model::FormatRegistry.register(
49
+ :json,
50
+ mapping_class: Lutaml::Json::Adapter::Mapping,
51
+ adapter_class: Lutaml::Json::Adapter::StandardAdapter,
52
+ transformer: Lutaml::Json::Adapter::Transform,
53
+ key_value: true,
54
+ adapter_options: {
55
+ available: %i[standard standard_json multi_json oj],
56
+ default: :standard,
57
+ },
58
+ )
59
+
60
+ require_relative "type/serializers"
61
+ Lutaml::Json::Type::Serializers.register_all!
data/lib/lutaml/json.rb CHANGED
@@ -1,62 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # JSON format module
4
- # Provides Lutaml::Json namespace for JSON serialization
5
-
6
- require "lutaml/model/runtime_compatibility"
3
+ # Public JSON format entrypoint. Loads the base model and the internal
4
+ # implementation. The internal file does not require the model back,
5
+ # which keeps the require graph acyclic.
7
6
  require_relative "model"
8
- require_relative "key_value"
9
-
10
- module Lutaml
11
- module Json
12
- class Error < StandardError; end
13
-
14
- require_relative "json/adapter/document"
15
- require_relative "json/adapter/mapping"
16
- require_relative "json/adapter/mapping_rule"
17
- require_relative "json/adapter/transform"
18
- require_relative "json/adapter/standard_adapter"
19
- Lutaml::Model::RuntimeCompatibility.require_native(
20
- "#{__dir__}/json/adapter/oj_adapter",
21
- "#{__dir__}/json/adapter/multi_json_adapter",
22
- )
23
- require_relative "json/schema"
24
-
25
- # Convenience aliases for common classes at the module level
26
- # Allows Lutaml::Json::Mapping to resolve to Lutaml::Json::Adapter::Mapping
27
- def self.const_missing(name)
28
- if Adapter.const_defined?(name, false)
29
- Adapter.const_get(name, false)
30
- else
31
- super
32
- end
33
- end
34
-
35
- # Detect available JSON adapters
36
- def self.detect_adapter
37
- return :standard if defined?(::JSON) && Lutaml::Model.opal?
38
- return :oj if defined?(::Oj)
39
- return :multi_json if defined?(::MultiJson)
40
- return :standard if defined?(::JSON)
41
-
42
- nil
43
- end
44
- end
45
- end
46
-
47
- # Register JSON format with the format registry
48
- Lutaml::Model::FormatRegistry.register(
49
- :json,
50
- mapping_class: Lutaml::Json::Adapter::Mapping,
51
- adapter_class: Lutaml::Json::Adapter::StandardAdapter,
52
- transformer: Lutaml::Json::Adapter::Transform,
53
- key_value: true,
54
- adapter_options: {
55
- available: %i[standard standard_json multi_json oj],
56
- default: :standard,
57
- },
58
- )
59
-
60
- # Register JSON type serializers
61
- require_relative "json/type/serializers"
62
- Lutaml::Json::Type::Serializers.register_all!
7
+ require_relative "json/format"
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Internal JSONL format implementation. Loaded from lib/lutaml/jsonl.rb
4
+ # (the public entrypoint) and from lib/lutaml/model.rb (so the model
5
+ # entrypoint triggers the registration side effects).
6
+ # No require_relative "model" here — keeps the require graph acyclic.
7
+
8
+ module Lutaml
9
+ module Jsonl
10
+ class Error < StandardError; end
11
+
12
+ autoload :Adapter, "#{__dir__}/adapter"
13
+ end
14
+ end
15
+
16
+ Lutaml::Model::FormatRegistry.register(
17
+ :jsonl,
18
+ mapping_class: Lutaml::Jsonl::Adapter::Mapping,
19
+ adapter_class: Lutaml::Jsonl::Adapter::StandardAdapter,
20
+ transformer: Lutaml::Jsonl::Adapter::Transform,
21
+ key_value: true,
22
+ )
data/lib/lutaml/jsonl.rb CHANGED
@@ -1,21 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # JSONL format module
4
- # Provides Lutaml::Jsonl namespace for JSONL serialization
5
-
6
- module Lutaml
7
- module Jsonl
8
- class Error < StandardError; end
9
-
10
- autoload :Adapter, "#{__dir__}/jsonl/adapter"
11
- end
12
- end
13
-
14
- # Register JSONL format with the format registry
15
- Lutaml::Model::FormatRegistry.register(
16
- :jsonl,
17
- mapping_class: Lutaml::Jsonl::Adapter::Mapping,
18
- adapter_class: Lutaml::Jsonl::Adapter::StandardAdapter,
19
- transformer: Lutaml::Jsonl::Adapter::Transform,
20
- key_value: true,
21
- )
3
+ # Public JSONL format entrypoint. Loads the base model and the internal
4
+ # implementation. The internal file does not require the model back,
5
+ # which keeps the require graph acyclic.
6
+ require_relative "model"
7
+ require_relative "jsonl/format"
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Internal KeyValue implementation. Loaded from lib/lutaml/key_value.rb
4
+ # (the public entrypoint) and from lib/lutaml/model.rb (so the model
5
+ # entrypoint triggers the registration side effects).
6
+ # No require_relative "model" here — keeps the require graph acyclic.
7
+
8
+ module Lutaml
9
+ module KeyValue
10
+ autoload :DataModel, "#{__dir__}/data_model"
11
+ autoload :Document, "#{__dir__}/document"
12
+ autoload :Mapping, "#{__dir__}/mapping"
13
+ autoload :MappingRule, "#{__dir__}/mapping_rule"
14
+ autoload :Transform, "#{__dir__}/transform"
15
+ autoload :Transformation, "#{__dir__}/transformation"
16
+ autoload :TransformationBuilder, "#{__dir__}/transformation_builder"
17
+ autoload :Adapter, "#{__dir__}/adapter"
18
+ end
19
+ end
20
+
21
+ # Register KeyValue transformation builders for all key-value formats
22
+ %i[json yaml toml hash].each do |format|
23
+ Lutaml::Model::TransformationRegistry.register_builder(
24
+ format, Lutaml::KeyValue::TransformationBuilder
25
+ )
26
+ end
@@ -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.
@@ -1,24 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Lutaml
4
- module KeyValue
5
- autoload :DataModel, "#{__dir__}/key_value/data_model"
6
- autoload :Document, "#{__dir__}/key_value/document"
7
- autoload :Mapping, "#{__dir__}/key_value/mapping"
8
- autoload :MappingRule, "#{__dir__}/key_value/mapping_rule"
9
- autoload :Transform, "#{__dir__}/key_value/transform"
10
- autoload :Transformation, "#{__dir__}/key_value/transformation"
11
- autoload :TransformationBuilder,
12
- "#{__dir__}/key_value/transformation_builder"
13
- autoload :Adapter, "#{__dir__}/key_value/adapter"
14
- end
15
- end
16
-
3
+ # Public KeyValue entrypoint. Loads the base model and the internal
4
+ # implementation. The internal file does not require the model back,
5
+ # which keeps the require graph acyclic.
17
6
  require_relative "model"
18
-
19
- # Register KeyValue transformation builders for all key-value formats
20
- %i[json yaml toml hash].each do |format|
21
- Lutaml::Model::TransformationRegistry.register_builder(
22
- format, Lutaml::KeyValue::TransformationBuilder
23
- )
24
- end
7
+ require_relative "key_value/format"
@@ -119,6 +119,17 @@ module Lutaml
119
119
  @resolver ||= GlobalContext.resolver
120
120
  end
121
121
 
122
+ # The value-shaping policy for this attribute. Constructed lazily so
123
+ # the collection/union/ref flags are settled; memoized because they
124
+ # are fixed after definition.
125
+ def value_policy
126
+ @value_policy ||= ValuePolicy.new(
127
+ collection: collection?,
128
+ union: union?,
129
+ reference: !@options[:ref_model_class].nil?,
130
+ )
131
+ end
132
+
122
133
  def type(context_or_register = nil)
123
134
  return if unresolved_type.nil?
124
135
 
@@ -394,7 +405,9 @@ instance_object = nil)
394
405
  instance_object)
395
406
  elsif options[:default].is_a?(Proc)
396
407
  if instance_object
397
- instance_object.instance_exec(&options[:default])
408
+ ::Lutaml::Model::Attribute.evaluating_default do
409
+ instance_object.instance_exec(&options[:default])
410
+ end
398
411
  else
399
412
  options[:default].call
400
413
  end
@@ -405,6 +418,22 @@ instance_object = nil)
405
418
  end
406
419
  end
407
420
 
421
+ # Marks the dynamic extent in which a default proc runs against a
422
+ # model instance, so Serialize#method_missing can fall back to the
423
+ # model class for methods the instance does not define (0.7.x
424
+ # compatibility, lutaml-model#745).
425
+ def self.evaluating_default
426
+ previous = Thread.current[:__lutaml_evaluating_default]
427
+ Thread.current[:__lutaml_evaluating_default] = true
428
+ yield
429
+ ensure
430
+ Thread.current[:__lutaml_evaluating_default] = previous
431
+ end
432
+
433
+ def self.default_evaluation?
434
+ Thread.current[:__lutaml_evaluating_default] == true
435
+ end
436
+
408
437
  def default_set?(register, instance_object = nil)
409
438
  !Utils.uninitialized?(default_value(register, instance_object))
410
439
  end
@@ -478,7 +507,10 @@ instance_object = nil)
478
507
  # Use the default value if the value is nil
479
508
  validate_required!(value)
480
509
 
481
- value = cast_value(default_value(register, instance_object), register) if value.nil?
510
+ if value.nil?
511
+ value = cast_value(default_value(register, instance_object),
512
+ register)
513
+ end
482
514
  resolved_type = type(register)
483
515
 
484
516
  valid_value!(value) &&
@@ -551,7 +583,8 @@ instance_object = nil)
551
583
  end
552
584
 
553
585
  def valid_collection!(value, caller)
554
- if collection_instance?(value) && !collection?
586
+ if collection_instance?(value) && !collection? &&
587
+ !value_policy.whole_value?(unresolved_type)
555
588
  raise Lutaml::Model::CollectionTrueMissingError.new(name,
556
589
  caller)
557
590
  end
@@ -632,7 +665,8 @@ instance_object = nil)
632
665
  else
633
666
  type(register)
634
667
  end
635
- if collection_instance?(value) || value.is_a?(Array)
668
+ if (collection_instance?(value) || value.is_a?(Array)) &&
669
+ !value_policy.whole_value?(resolved_type)
636
670
  merged_opts = options.merge(resolved_type: resolved_type,
637
671
  converted: true)
638
672
  return build_collection(value.map do |v|
@@ -481,8 +481,8 @@ lutaml_register: Lutaml::Model::Config.default_register)
481
481
  self.class.new(items - other.items)
482
482
  end
483
483
 
484
- def each(&)
485
- collection.each(&)
484
+ def each(&block)
485
+ collection.each(&block)
486
486
  end
487
487
 
488
488
  def size
@@ -192,7 +192,7 @@ module Lutaml
192
192
  # @param args [Array] Arguments (ignored for options)
193
193
  # @param block [Proc] Block (ignored for options)
194
194
  # @return [Object] The option value or nil
195
- def method_missing(method_name, *args, &)
195
+ def method_missing(method_name, *args, &block)
196
196
  # Check if this is an option key
197
197
  if options.key?(method_name)
198
198
  return options[method_name]
@@ -42,8 +42,8 @@ module Lutaml
42
42
  # Config.with_adapter(xml: :nokogiri, toml: :tomlib) do
43
43
  # MyModel.from_xml(data)
44
44
  # end
45
- def with_adapter(**overrides, &)
46
- AdapterScope.with(overrides, &)
45
+ def with_adapter(**overrides, &block)
46
+ AdapterScope.with(overrides, &block)
47
47
  end
48
48
 
49
49
  # Delegate configure to Configuration
@@ -39,8 +39,8 @@ module Lutaml
39
39
  end
40
40
 
41
41
  # Pattern A: declare discriminator routing
42
- def dispatch_by(discriminator, &)
43
- routes = DispatchBuilder.new.evaluate(&)
42
+ def dispatch_by(discriminator, &block)
43
+ routes = DispatchBuilder.new.evaluate(&block)
44
44
  @rules << DispatchBlock.new(discriminator, routes)
45
45
  end
46
46
 
@@ -20,9 +20,9 @@ module Lutaml
20
20
 
21
21
  # Helper builder for the dispatch_by block
22
22
  class DispatchBuilder
23
- def evaluate(&)
23
+ def evaluate(&block)
24
24
  @routes = {}
25
- instance_eval(&)
25
+ instance_eval(&block)
26
26
  @routes
27
27
  end
28
28
 
@@ -18,8 +18,8 @@ module Lutaml
18
18
  @errors.empty?
19
19
  end
20
20
 
21
- def each(&)
22
- @errors.each(&)
21
+ def each(&block)
22
+ @errors.each(&block)
23
23
  end
24
24
 
25
25
  def full_messages
@@ -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
@@ -67,6 +67,9 @@ module Lutaml
67
67
  )
68
68
  @name = name
69
69
  @to = to
70
+ # Dynamic symbol built per call allocated ~10% of parse objects on
71
+ # attribute-heavy documents; `to` is immutable, so build it once.
72
+ @setter_name = :"#{to}="
70
73
  @to_instance = to_instance
71
74
  @as_attribute = as_attribute
72
75
  @render_nil = render_nil
@@ -457,7 +460,7 @@ module Lutaml
457
460
  end
458
461
 
459
462
  def assign_value(model, value)
460
- model.public_send(:"#{to}=", value)
463
+ model.public_send(@setter_name, value)
461
464
  end
462
465
  end
463
466
  end
@@ -43,7 +43,7 @@ module Lutaml
43
43
  to: nil,
44
44
  transform: nil,
45
45
  reverse_transform: nil,
46
- &
46
+ &block
47
47
  )
48
48
  map(
49
49
  from: from,
@@ -51,7 +51,7 @@ module Lutaml
51
51
  transform: transform,
52
52
  reverse_transform: reverse_transform,
53
53
  collection: true,
54
- &
54
+ &block
55
55
  )
56
56
  end
57
57
 
@@ -114,8 +114,8 @@ if Lutaml::Model::RuntimeCompatibility.opal?
114
114
 
115
115
  # Minimal method_missing so the WeakRef quacks like its target
116
116
  # for the Store's index lookups.
117
- def method_missing(name, *, &)
118
- @__target__.public_send(name, *, &)
117
+ def method_missing(name, ...)
118
+ @__target__.public_send(name, ...)
119
119
  end
120
120
 
121
121
  def respond_to_missing?(name, include_private = false)
@@ -36,7 +36,8 @@ module Lutaml
36
36
 
37
37
  def load
38
38
  Dir.mktmpdir do |dir|
39
- FileWriter.write(@output, dir, registry_generator: @registry_generator)
39
+ FileWriter.write(@output, dir,
40
+ registry_generator: @registry_generator)
40
41
  require File.join(dir, "#{registry_basename}_registry")
41
42
  call_register_all
42
43
  end
@@ -21,12 +21,12 @@ module Lutaml
21
21
  resolve_polymorphic_base_types!
22
22
  end
23
23
 
24
- def each(&)
25
- @definitions.each(&)
24
+ def each(&block)
25
+ @definitions.each(&block)
26
26
  end
27
27
 
28
- def transform_values(&)
29
- @definitions.transform_values(&)
28
+ def transform_values(&block)
29
+ @definitions.transform_values(&block)
30
30
  end
31
31
 
32
32
  def [](name)
@@ -7,7 +7,8 @@ module Lutaml
7
7
  # An XML namespace declaration (subclass of
8
8
  # Lutaml::Xml::W3c::XmlNamespace).
9
9
  class Namespace
10
- attr_accessor :class_name, :uri, :prefix_default, :element_form_default
10
+ attr_accessor :class_name, :uri, :prefix_default,
11
+ :element_form_default
11
12
 
12
13
  def initialize(class_name:, uri:, prefix_default: nil,
13
14
  element_form_default: nil)
@@ -45,7 +45,8 @@ module Lutaml
45
45
  )
46
46
  if registry
47
47
  registry_name = module_path.split("/").last
48
- File.write(File.join(@dir, "#{registry_name}_registry.rb"), registry)
48
+ File.write(File.join(@dir, "#{registry_name}_registry.rb"),
49
+ registry)
49
50
  end
50
51
 
51
52
  write_sources_to(full_dir)
@@ -57,7 +58,9 @@ module Lutaml
57
58
  end
58
59
 
59
60
  def write_sources_to(target_dir)
60
- @output.sources.each { |name, src| write_source(target_dir, name, src) }
61
+ @output.sources.each do |name, src|
62
+ write_source(target_dir, name, src)
63
+ end
61
64
  end
62
65
 
63
66
  def write_source(target_dir, name, src)
@@ -10,11 +10,12 @@ module Lutaml
10
10
  # (Union, RestrictedType, Namespace). Model has its own constructor
11
11
  # because it computes an opt-out (module-wrappable) namespace.
12
12
  class Base
13
- def self.render(spec, **)
14
- new(spec, **).render
13
+ def self.render(spec, **options)
14
+ new(spec, **options).render
15
15
  end
16
16
 
17
- def initialize(spec, indent: 2, module_namespace: nil, register_id: :default)
17
+ def initialize(spec, indent: 2, module_namespace: nil,
18
+ register_id: :default)
18
19
  @spec = spec
19
20
  @indent = indent.is_a?(Integer) ? " " * indent : indent
20
21
  @extended_indent = @indent * 2
@@ -29,7 +29,9 @@ module Lutaml
29
29
  def render_one(member, indent)
30
30
  case member
31
31
  when Definitions::Sequence then render_sequence(member, indent)
32
- when Definitions::Choice then member.alternatives.map { |a| render_one(a, indent) }.join
32
+ when Definitions::Choice then member.alternatives.map do |a|
33
+ render_one(a, indent)
34
+ end.join
33
35
  when Definitions::Attribute then render_attribute(member, indent)
34
36
  when Definitions::GroupImport then "#{indent}import_model_mappings :#{member.name}\n"
35
37
  end
@@ -37,7 +39,9 @@ module Lutaml
37
39
 
38
40
  def render_sequence(sequence, indent)
39
41
  inner_indent = indent + @base_indent
40
- inner = sequence.members.map { |m| render_one(m, inner_indent) }.join
42
+ inner = sequence.members.map do |m|
43
+ render_one(m, inner_indent)
44
+ end.join
41
45
  "#{indent}sequence do\n#{inner}#{indent}end\n"
42
46
  end
43
47
 
@@ -63,7 +67,9 @@ module Lutaml
63
67
  def simple_content_attribute_mappings
64
68
  return "" unless @simple_content
65
69
 
66
- @simple_content.additional_attributes.map { |a| render_one(a, @indent) }.join
70
+ @simple_content.additional_attributes.map do |a|
71
+ render_one(a, @indent)
72
+ end.join
67
73
  end
68
74
  end
69
75
  end