lutaml-model 0.8.0 → 0.8.2

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-repos.json +9 -0
  3. data/.github/workflows/downstream-performance.yml +0 -3
  4. data/.rubocop_todo.yml +18 -186
  5. data/README.adoc +212 -15
  6. data/bench/bench_xmi.rb +6 -6
  7. data/bench/gate_config.rb +2 -9
  8. data/docs/_pages/configuration.adoc +155 -41
  9. data/docs/_pages/serialization_adapters.adoc +65 -14
  10. data/docs/index.adoc +3 -1
  11. data/docs/yamls_sequence.adoc +335 -0
  12. data/lib/lutaml/hash_format.rb +4 -0
  13. data/lib/lutaml/json/adapter/multi_json_adapter.rb +4 -2
  14. data/lib/lutaml/json/adapter/oj_adapter.rb +4 -2
  15. data/lib/lutaml/json.rb +4 -0
  16. data/lib/lutaml/key_value/adapter/json/multi_json_adapter.rb +4 -2
  17. data/lib/lutaml/key_value/adapter/json/oj_adapter.rb +4 -2
  18. data/lib/lutaml/model/adapter_resolver.rb +410 -0
  19. data/lib/lutaml/model/adapter_scope.rb +64 -0
  20. data/lib/lutaml/model/config.rb +84 -21
  21. data/lib/lutaml/model/configuration.rb +17 -249
  22. data/lib/lutaml/model/format_registry.rb +44 -117
  23. data/lib/lutaml/model/mapping/listener.rb +4 -2
  24. data/lib/lutaml/model/serialize/format_conversion.rb +42 -3
  25. data/lib/lutaml/model/serialize.rb +4 -2
  26. data/lib/lutaml/model/services/base.rb +4 -2
  27. data/lib/lutaml/model/version.rb +1 -1
  28. data/lib/lutaml/model.rb +2 -0
  29. data/lib/lutaml/toml.rb +10 -3
  30. data/lib/lutaml/xml/serialization/instance_methods.rb +6 -0
  31. data/lib/lutaml/xml.rb +3 -4
  32. data/lib/lutaml/yaml.rb +4 -0
  33. data/lib/lutaml/yamls/adapter/mapping.rb +7 -0
  34. data/lib/lutaml/yamls/adapter/standard_adapter.rb +23 -2
  35. data/lib/lutaml/yamls/adapter/transform.rb +105 -7
  36. data/lib/lutaml/yamls/adapter/yamls_sequence.rb +20 -0
  37. data/lib/lutaml/yamls/adapter/yamls_sequence_rule.rb +48 -0
  38. data/lib/lutaml/yamls/adapter.rb +2 -0
  39. data/spec/fixtures/geolexica_v2_concept.rb +136 -0
  40. data/spec/fixtures/geolexica_v2_sample.yaml +36 -0
  41. data/spec/fixtures/geolexica_v2_sample2.yaml +38 -0
  42. data/spec/fixtures/yamls_range_concept.rb +139 -0
  43. data/spec/lutaml/model/xml_decoupling_spec.rb +5 -4
  44. data/spec/lutaml/model/yamls_range_spec.rb +393 -0
  45. data/spec/lutaml/model/yamls_sequence_spec.rb +245 -0
  46. data/spec/spec_helper.rb +5 -0
  47. metadata +13 -3
  48. data/bench/bench_uniword.rb +0 -69
@@ -41,7 +41,7 @@ module Lutaml
41
41
  # @return [Object] The deserialized model instance
42
42
  def from(format, data, options = {})
43
43
  Instrumentation.instrument(:from, model: name, format: format) do
44
- adapter = Lutaml::Model::Config.adapter_for(format)
44
+ adapter = resolve_adapter(format, options.delete(:adapter))
45
45
 
46
46
  raise Lutaml::Model::FormatAdapterNotSpecifiedError.new(format) if adapter.nil?
47
47
 
@@ -130,7 +130,7 @@ module Lutaml
130
130
  # @param options [Hash] Additional options
131
131
  # @return [Object] The model instance
132
132
  def of(format, doc, options = {})
133
- if doc.is_a?(Array) && format != :jsonl
133
+ if doc.is_a?(Array) && !array_passthrough_format?(format)
134
134
  return doc.map { |item| send(:"of_#{format}", item) }
135
135
  end
136
136
 
@@ -156,6 +156,23 @@ module Lutaml
156
156
  # No-op by default; XML overrides via prepend
157
157
  end
158
158
 
159
+ # Whether this format+model combination requires the parsed array
160
+ # to pass through to the transformer as a whole (not split per element).
161
+ # YAMLS with sequence definitions needs the full document array.
162
+ #
163
+ # @param format [Symbol] The format
164
+ # @return [Boolean]
165
+ def array_passthrough_format?(format)
166
+ return true if format == :jsonl
167
+
168
+ if format == :yamls
169
+ mapping = mappings[format]
170
+ return true if mapping.respond_to?(:yamls_sequence) && mapping.yamls_sequence
171
+ end
172
+
173
+ false
174
+ end
175
+
159
176
  # Serialize a model instance to a format
160
177
  #
161
178
  # @param format [Symbol] The format to serialize to
@@ -171,8 +188,13 @@ module Lutaml
171
188
  # @return [String] The serialized output
172
189
  def to(format, instance, options = {})
173
190
  Instrumentation.instrument(:to, model: name, format: format) do
191
+ adapter_override = options.is_a?(Hash) && options.delete(:adapter)
192
+ if adapter_override && options.is_a?(Hash)
193
+ options[:_adapter_override] =
194
+ true
195
+ end
174
196
  value = public_send(:"as_#{format}", instance, options)
175
- adapter = Lutaml::Model::Config.adapter_for(format)
197
+ adapter = resolve_adapter(format, adapter_override)
176
198
 
177
199
  # Hook for format-specific options preparation (e.g., XML prefix/namespace/declaration)
178
200
  options = prepare_to_options(format, instance, options)
@@ -292,6 +314,23 @@ module Lutaml
292
314
  # If a root element is needed, declare it explicitly in xml block
293
315
  end
294
316
  end
317
+
318
+ private
319
+
320
+ # Resolve adapter class for a format operation.
321
+ #
322
+ # @param format [Symbol] the format name
323
+ # @param adapter_override [Symbol, Class, nil] per-operation adapter override
324
+ # @return [Class, nil] the adapter class
325
+ def resolve_adapter(format, adapter_override)
326
+ if adapter_override.is_a?(Class)
327
+ adapter_override
328
+ elsif adapter_override
329
+ AdapterResolver.resolved_adapter_class(format, adapter_override)
330
+ else
331
+ AdapterResolver.adapter_for(format)
332
+ end
333
+ end
295
334
  end
296
335
  end
297
336
  end
@@ -159,16 +159,18 @@ module Lutaml
159
159
  @using_default[attribute_name]
160
160
  end
161
161
 
162
- def method_missing(method_name, *)
162
+ # rubocop:disable Style/ArgumentsForwarding -- anonymous * requires Ruby 3.2+, but required_ruby_version >= 3.0
163
+ def method_missing(method_name, *args)
163
164
  if method_name.to_s.end_with?("=") && attribute_exist?(method_name)
164
165
  define_singleton_method(method_name) do |value|
165
166
  instance_variable_set(:"@#{method_name.to_s.chomp('=')}", value)
166
167
  end
167
- send(method_name, *)
168
+ send(method_name, *args)
168
169
  else
169
170
  super
170
171
  end
171
172
  end
173
+ # rubocop:enable Style/ArgumentsForwarding
172
174
 
173
175
  def respond_to_missing?(method_name, include_private = false)
174
176
  (method_name.to_s.end_with?("=") && attribute_exist?(method_name)) ||
@@ -2,8 +2,10 @@ module Lutaml
2
2
  module Model
3
3
  module Services
4
4
  class Base
5
- def self.call(*)
6
- new(*).call
5
+ # rubocop:disable Style/ArgumentsForwarding -- anonymous * requires Ruby 3.2+
6
+ def self.call(*args)
7
+ new(*args).call
8
+ # rubocop:enable Style/ArgumentsForwarding
7
9
  end
8
10
  end
9
11
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Model
5
- VERSION = "0.8.0"
5
+ VERSION = "0.8.2"
6
6
  end
7
7
  end
data/lib/lutaml/model.rb CHANGED
@@ -28,6 +28,8 @@ module Lutaml
28
28
  autoload :ContextRegistry, "#{__dir__}/model/context_registry"
29
29
  autoload :ImportRegistry, "#{__dir__}/model/import_registry"
30
30
  autoload :GlobalContext, "#{__dir__}/model/global_context"
31
+ autoload :AdapterResolver, "#{__dir__}/model/adapter_resolver"
32
+ autoload :AdapterScope, "#{__dir__}/model/adapter_scope"
31
33
  autoload :Utils, "#{__dir__}/model/utils"
32
34
  autoload :Serializable, "#{__dir__}/model/serializable"
33
35
  autoload :Error, "#{__dir__}/model/error"
data/lib/lutaml/toml.rb CHANGED
@@ -30,12 +30,19 @@ Lutaml::Model::FormatRegistry.register(
30
30
  adapter_class: nil,
31
31
  transformer: Lutaml::Toml::Adapter::Transform,
32
32
  key_value: true,
33
+ adapter_options: if Lutaml::Model::RuntimeCompatibility.opal?
34
+ nil
35
+ else
36
+ {
37
+ available: %i[tomlib toml_rb],
38
+ default: Lutaml::Model::RuntimeCompatibility.windows? ? :toml_rb : :tomlib,
39
+ }
40
+ end,
33
41
  )
34
42
 
35
43
  # Register TOML type serializers
36
44
  require_relative "toml/type/serializers"
37
45
  Lutaml::Toml::Type::Serializers.register_all!
38
46
 
39
- if (adapter = Lutaml::Model::Toml.detect_toml_adapter)
40
- Lutaml::Model::Config.toml_adapter_type = adapter
41
- end
47
+ # Auto-detection is now handled lazily by AdapterResolver on first use.
48
+ # No eager adapter selection at require time.
@@ -203,6 +203,12 @@ module Lutaml
203
203
  def prepare_instance_format_options(format, options)
204
204
  return super unless format == :xml
205
205
 
206
+ # Force eager plan building when adapter is being overridden,
207
+ # to dereference adapter-specific native nodes before the switch.
208
+ if @pending_plan_root_element && options[:_adapter_override]
209
+ import_declaration_plan
210
+ end
211
+
206
212
  # Handle prefix option (converts to use_prefix for transformation phase)
207
213
  if options.key?(:prefix)
208
214
  prefix_option = options[:prefix]
data/lib/lutaml/xml.rb CHANGED
@@ -279,10 +279,9 @@ Lutaml::Model::GlobalContext.register_format_registry(
279
279
  # Eagerly load W3C namespace definitions (has registration side effects)
280
280
  require_relative "xml/w3c"
281
281
 
282
- # Auto-detect and set default XML adapter
283
- if (adapter = Lutaml::Xml.detect_xml_adapter)
284
- Lutaml::Model::Config.xml_adapter_type = adapter
285
- end
282
+ # Auto-detection is now handled lazily by AdapterResolver on first use.
283
+ # No eager adapter selection at require time — libraries can configure
284
+ # their preferred adapter before any XML operations occur.
286
285
 
287
286
  # Namespace identifier validation:
288
287
  # - URIs (http://..., urn:...) are valid namespace names per W3C XML
data/lib/lutaml/yaml.rb CHANGED
@@ -19,6 +19,10 @@ Lutaml::Model::FormatRegistry.register(
19
19
  adapter_class: Lutaml::Yaml::Adapter::StandardAdapter,
20
20
  transformer: Lutaml::Yaml::Adapter::Transform,
21
21
  key_value: true,
22
+ adapter_options: {
23
+ available: %i[standard standard_yaml],
24
+ default: :standard,
25
+ },
22
26
  )
23
27
 
24
28
  # Register YAML type serializers
@@ -4,10 +4,17 @@ module Lutaml
4
4
  module Yamls
5
5
  module Adapter
6
6
  class Mapping < Lutaml::KeyValue::Mapping
7
+ attr_reader :yamls_sequence
8
+
7
9
  def initialize
8
10
  super(:yaml)
9
11
  end
10
12
 
13
+ def sequence(&)
14
+ @yamls_sequence = YamlsSequence.new
15
+ @yamls_sequence.instance_eval(&)
16
+ end
17
+
11
18
  def deep_dup
12
19
  self.class.new.tap do |new_mapping|
13
20
  new_mapping.mappings = duplicate_mappings
@@ -9,13 +9,33 @@ module Lutaml
9
9
  FORMAT_SYMBOL = :yamls
10
10
 
11
11
  def self.parse(yamls, _options = {})
12
+ parse_with_stream(yamls)
13
+ end
14
+
15
+ def self.parse_with_stream(yamls)
16
+ results = []
17
+
18
+ YAML.load_stream(yamls) do |doc|
19
+ next if doc.nil?
20
+
21
+ results << doc
22
+ end
23
+
24
+ results
25
+ rescue Psych::SyntaxError => e
26
+ warn "Skipping invalid yaml: #{e.message}"
27
+ parse_with_split(yamls)
28
+ end
29
+
30
+ def self.parse_with_split(yamls)
12
31
  results = []
13
32
 
14
- yamls.split(/^---\n/).each do |yaml|
33
+ yamls.split(/^---\s*$/).each do |yaml|
15
34
  next if yaml.strip.empty?
16
35
 
17
36
  begin
18
- results << YAML.safe_load(yaml, aliases: true)
37
+ doc = YAML.safe_load(yaml, aliases: true)
38
+ results << doc unless doc.nil?
19
39
  rescue Psych::SyntaxError => e
20
40
  warn "Skipping invalid yaml: #{e.message}"
21
41
  end
@@ -23,6 +43,7 @@ module Lutaml
23
43
 
24
44
  results
25
45
  end
46
+ private_class_method :parse_with_stream, :parse_with_split
26
47
 
27
48
  def to_yamls(*_args)
28
49
  (@yamls || []).map do |yaml|
@@ -8,17 +8,115 @@ module Lutaml
8
8
  mappings = defined_mappings_for(:yamls) || mappings_for(:yaml,
9
9
  lutaml_register)
10
10
 
11
- super(data, format, options.merge(mappings: mappings))
11
+ if mappings.is_a?(Mapping) && mappings.yamls_sequence
12
+ data_to_model_with_sequence(data, format, mappings.yamls_sequence,
13
+ options)
14
+ else
15
+ super(data, format, options.merge(mappings: mappings))
16
+ end
12
17
  end
13
18
 
14
19
  def model_to_data(instance, _format, options = {})
15
- # For YAMLS collections, use yamls mappings for this collection
16
- # But let nested instances use their own yaml mappings
17
- # by passing :yaml format without forcing mappings parameter
18
- defined_mappings_for(:yamls) || mappings_for(:yaml, lutaml_register)
20
+ mappings = defined_mappings_for(:yamls) || mappings_for(:yaml,
21
+ lutaml_register)
22
+
23
+ if mappings.is_a?(Mapping) && mappings.yamls_sequence
24
+ model_to_data_with_sequence(instance, mappings.yamls_sequence)
25
+ else
26
+ defined = defined_mappings_for(:yamls) || mappings_for(:yaml,
27
+ lutaml_register)
28
+ super(instance, :yaml, options.merge(mappings: defined))
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def data_to_model_with_sequence(data_array, format, sequence, options)
35
+ register = lutaml_register
36
+ child_register = Lutaml::Model::Register.resolve_for_child(
37
+ model_class, register
38
+ )
39
+
40
+ instance = if model_class.include?(Lutaml::Model::Serialize)
41
+ model_class.new(lutaml_register: child_register)
42
+ else
43
+ model_class.new
44
+ end
45
+ root_and_parent_assignment(instance, options)
46
+
47
+ sequence.rules.each do |rule|
48
+ docs = extract_docs_for_rule(data_array, rule)
49
+ next if docs.nil?
50
+ next if docs.is_a?(Array) && docs.empty?
51
+
52
+ if rule.singular?
53
+ doc = docs.is_a?(Array) ? docs.first : docs
54
+ value = deserialize_single_doc(doc, rule.type, format,
55
+ register, instance)
56
+ rule.assign_value(instance, value)
57
+ else
58
+ values = docs.map do |doc|
59
+ deserialize_single_doc(doc, rule.type, format, register,
60
+ instance)
61
+ end
62
+ rule.assign_value(instance, values)
63
+ end
64
+ end
65
+
66
+ instance
67
+ end
68
+
69
+ def extract_docs_for_rule(data_array, rule)
70
+ size = data_array.size
71
+ return nil if size.zero?
72
+
73
+ case rule.position
74
+ when Integer
75
+ idx = rule.position.negative? ? rule.position + size : rule.position
76
+ data_array[idx]
77
+ when Range
78
+ start_idx = rule.position.begin.negative? ? rule.position.begin + size : rule.position.begin
79
+ end_idx = rule.position.end
80
+ end_idx = size - 1 if end_idx.nil?
81
+ end_idx = end_idx + size if end_idx.negative?
82
+ end_idx = size - 1 if end_idx > size - 1
83
+ start_idx = 0 if start_idx.negative?
84
+ return nil if start_idx > end_idx
85
+
86
+ data_array[start_idx..end_idx]
87
+ end
88
+ end
89
+
90
+ def deserialize_single_doc(doc, type, _format, register, parent)
91
+ transformer = Lutaml::Model::Config.transformer_for(:yaml)
92
+ transformer.data_to_model(
93
+ type, doc, :yaml,
94
+ register: register,
95
+ lutaml_parent: parent,
96
+ lutaml_root: parent.lutaml_root || parent
97
+ )
98
+ end
99
+
100
+ def model_to_data_with_sequence(instance, sequence)
101
+ results = []
102
+
103
+ sequence.rules.each do |rule|
104
+ value = rule.read_value(instance)
105
+ next if value.nil?
106
+
107
+ if rule.singular?
108
+ results << serialize_single_model(value)
109
+ else
110
+ value.each { |item| results << serialize_single_model(item) }
111
+ end
112
+ end
113
+
114
+ results
115
+ end
19
116
 
20
- # Override format to :yaml - nested instances will auto-select yaml mappings
21
- super(instance, :yaml, options)
117
+ def serialize_single_model(item)
118
+ transformer = Lutaml::Model::Config.transformer_for(:yaml)
119
+ transformer.model_to_data(item.class, item, :yaml)
22
120
  end
23
121
  end
24
122
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Yamls
5
+ module Adapter
6
+ class YamlsSequence
7
+ attr_reader :rules
8
+
9
+ def initialize
10
+ @rules = []
11
+ end
12
+
13
+ def map_document(position, to:, type:, collection: false)
14
+ @rules << YamlsSequenceRule.new(position, to: to, type: type,
15
+ collection: collection)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Yamls
5
+ module Adapter
6
+ class YamlsSequenceRule
7
+ attr_reader :position, :to, :type, :collection
8
+
9
+ def initialize(position, to:, type:, collection: false)
10
+ @position = position
11
+ @to = to
12
+ @type = type
13
+ @collection = collection
14
+ end
15
+
16
+ def resolve_range(doc_count)
17
+ return nil unless doc_count.positive?
18
+
19
+ case position
20
+ when Integer
21
+ idx = position.negative? ? position + doc_count : position
22
+ idx..idx
23
+ when Range
24
+ start_idx = position.begin.negative? ? position.begin + doc_count : position.begin
25
+ end_idx = position.end
26
+ end_idx = doc_count - 1 if end_idx.nil?
27
+ end_idx = end_idx + doc_count if end_idx.negative?
28
+ end_idx = doc_count - 1 if end_idx > doc_count - 1
29
+ start_idx = 0 if start_idx.negative?
30
+ start_idx..end_idx
31
+ end
32
+ end
33
+
34
+ def singular?
35
+ !collection
36
+ end
37
+
38
+ def assign_value(instance, value)
39
+ instance.public_send(:"#{to}=", value)
40
+ end
41
+
42
+ def read_value(instance)
43
+ instance.public_send(to)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -7,6 +7,8 @@ module Lutaml
7
7
  autoload :Mapping, "#{__dir__}/adapter/mapping"
8
8
  autoload :MappingRule, "#{__dir__}/adapter/mapping_rule"
9
9
  autoload :Transform, "#{__dir__}/adapter/transform"
10
+ autoload :YamlsSequence, "#{__dir__}/adapter/yamls_sequence"
11
+ autoload :YamlsSequenceRule, "#{__dir__}/adapter/yamls_sequence_rule"
10
12
  autoload :StandardAdapter, "#{__dir__}/adapter/standard_adapter"
11
13
  end
12
14
  end
@@ -0,0 +1,136 @@
1
+ require_relative "../../lib/lutaml/model"
2
+
3
+ module GeolexicaV2
4
+ # --- Leaf types ---
5
+
6
+ class ContentBlock < Lutaml::Model::Serializable
7
+ attribute :content, :string
8
+
9
+ yaml do
10
+ map "content", to: :content
11
+ end
12
+ end
13
+
14
+ class TermDesignation < Lutaml::Model::Serializable
15
+ attribute :type, :string
16
+ attribute :normative_status, :string
17
+ attribute :designation, :string
18
+
19
+ yaml do
20
+ map "type", to: :type
21
+ map "normative_status", to: :normative_status
22
+ map "designation", to: :designation
23
+ end
24
+ end
25
+
26
+ class Locality < Lutaml::Model::Serializable
27
+ attribute :type, :string
28
+ attribute :reference_from, :string
29
+
30
+ yaml do
31
+ map "type", to: :type
32
+ map "reference_from", to: :reference_from
33
+ end
34
+ end
35
+
36
+ class SourceOrigin < Lutaml::Model::Serializable
37
+ attribute :ref, :string
38
+ attribute :locality, Locality
39
+ attribute :link, :string
40
+
41
+ yaml do
42
+ map "ref", to: :ref
43
+ map "locality", to: :locality
44
+ map "link", to: :link
45
+ end
46
+ end
47
+
48
+ class Source < Lutaml::Model::Serializable
49
+ attribute :origin, SourceOrigin
50
+ attribute :type, :string
51
+
52
+ yaml do
53
+ map "origin", to: :origin
54
+ map "type", to: :type
55
+ end
56
+ end
57
+
58
+ # --- Document 0: Concept Index ---
59
+
60
+ class ConceptIndexData < Lutaml::Model::Serializable
61
+ attribute :identifier, :string
62
+ attribute :localized_concepts, :hash
63
+
64
+ yaml do
65
+ map "identifier", to: :identifier
66
+ map "localized_concepts", to: :localized_concepts
67
+ end
68
+ end
69
+
70
+ class ConceptIndex < Lutaml::Model::Serializable
71
+ attribute :data, ConceptIndexData
72
+ attribute :id, :string
73
+
74
+ yaml do
75
+ map "data", to: :data
76
+ map "id", to: :id
77
+ end
78
+ end
79
+
80
+ # --- Document 1: Localized Concept ---
81
+
82
+ class LocalizedConceptData < Lutaml::Model::Serializable
83
+ attribute :definition, ContentBlock, collection: true
84
+ attribute :examples, ContentBlock, collection: true
85
+ attribute :notes, ContentBlock, collection: true
86
+ attribute :sources, Source, collection: true
87
+ attribute :terms, TermDesignation, collection: true
88
+ attribute :language_code, :string
89
+ attribute :entry_status, :string
90
+
91
+ yaml do
92
+ map "definition", to: :definition, render_empty: true
93
+ map "examples", to: :examples, render_empty: true
94
+ map "notes", to: :notes, render_empty: true
95
+ map "sources", to: :sources, render_empty: true
96
+ map "terms", to: :terms
97
+ map "language_code", to: :language_code
98
+ map "entry_status", to: :entry_status
99
+ end
100
+ end
101
+
102
+ class LocalizedConcept < Lutaml::Model::Serializable
103
+ attribute :data, LocalizedConceptData
104
+ attribute :id, :string
105
+
106
+ yaml do
107
+ map "data", to: :data
108
+ map "id", to: :id
109
+ end
110
+ end
111
+
112
+ # --- Managed Concept: YAMLS sequence of ConceptIndex + LocalizedConcept ---
113
+
114
+ class ManagedConcept < Lutaml::Model::Serializable
115
+ attribute :index, ConceptIndex
116
+ attribute :localized, LocalizedConcept, collection: true
117
+
118
+ yamls do
119
+ sequence do
120
+ map_document 0, to: :index, type: ConceptIndex
121
+ map_document 1.., to: :localized, type: LocalizedConcept,
122
+ collection: true
123
+ end
124
+ end
125
+ end
126
+
127
+ # --- Collection of ManagedConcepts (directory of v2 files) ---
128
+
129
+ class ManagedConceptCollection < Lutaml::Model::Collection
130
+ instances :concepts, ManagedConcept
131
+
132
+ yamls do
133
+ map_instances to: :concepts
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,36 @@
1
+ ---
2
+ data:
3
+ identifier: 3.5.8.8
4
+ localized_concepts:
5
+ eng: fbe1444a-7c11-555e-bb1b-680a4e6f2502
6
+ id: 0171b198-d068-53d9-8741-fb87e6755d62
7
+
8
+ ---
9
+ data:
10
+ definition:
11
+ - content: characteristic of a {{urn:iso:std:iso:14812:3.5.8.1,financial model}}
12
+ that requires {{urn:iso:std:iso:14812:3.5.3.4,user,users}} to enter into an
13
+ agreement prior to receiving {{urn:iso:std:iso:14812:3.5.2.1,service,services}}
14
+ examples: []
15
+ notes:
16
+ - content: The agreement can be associated with fees.
17
+ - content: The agreement can be minimal, such as collecting user information for
18
+ business purposes.
19
+ - content: The membership can be granted as a part of a broader agreement. For example,
20
+ a university bus {{urn:iso:std:iso:14812:3.1.2.1,system}} can restrict access
21
+ to students and faculty.
22
+ sources:
23
+ - origin:
24
+ ref: ISO/TS 14812:2022
25
+ locality:
26
+ type: clause
27
+ reference_from: 3.5.8.8
28
+ link: https://www.iso.org/standard/79779.html
29
+ type: authoritative
30
+ terms:
31
+ - type: expression
32
+ normative_status: preferred
33
+ designation: membership-based
34
+ language_code: eng
35
+ entry_status: valid
36
+ id: fbe1444a-7c11-555e-bb1b-680a4e6f2502
@@ -0,0 +1,38 @@
1
+ ---
2
+ data:
3
+ identifier: 3.7.1.5
4
+ localized_concepts:
5
+ eng: 0e4dd58e-d197-57af-a4fb-55653e46540d
6
+ id: 01da7814-e090-5c79-8e88-04a40532da50
7
+
8
+ ---
9
+ data:
10
+ definition:
11
+ - content: "{{urn:iso:std:iso:14812:3.7.1.4,vehicle input device,input device}}
12
+ designed to be physically {{urn:iso:std:iso:14812:3.2.3.6,connected}} to a {{urn:iso:std:iso:14812:3.7.1.1,vehicle}}
13
+ and to remain connected even when the vehicle is not in use"
14
+ examples: []
15
+ notes:
16
+ - content: Built-in input devices include devices that can be temporarily {{urn:iso:std:iso:14812:3.7.4.3,disconnected}}
17
+ for security reasons (e.g. some radios are equipped with detachable front panels).
18
+ - content: Built-in input devices are typically considered to be a part of the vehicle.
19
+ - content: Built-in input devices require a maintenance operation to connect or
20
+ disconnect.
21
+ sources:
22
+ - origin:
23
+ ref: ISO/TS 14812:2022
24
+ locality:
25
+ type: clause
26
+ reference_from: 3.7.1.5
27
+ link: https://www.iso.org/standard/79779.html
28
+ type: authoritative
29
+ terms:
30
+ - type: expression
31
+ normative_status: preferred
32
+ designation: built-in vehicle input device
33
+ - type: expression
34
+ normative_status: preferred
35
+ designation: built-in input device
36
+ language_code: eng
37
+ entry_status: valid
38
+ id: 0e4dd58e-d197-57af-a4fb-55653e46540d