Class: Opencdd::Entity::Yaml
- Inherits:
-
Lutaml::Model::Serializable
- Object
- Lutaml::Model::Serializable
- Opencdd::Entity::Yaml
- Defined in:
- lib/opencdd/entity/yaml.rb
Overview
CDD-native YAML serialization model.
This is the deepened YAML adapter: the conversion logic that
translates between semantic CDD attribute names (preferred_name,
superclass, class_type) and IEC 62656-1 wire-format keys
(MDC_P004, MDC_P010, MDC_P011) lives here, inside Entity's
namespace. Entity delegates to_yaml / from_yaml to this
class.
Why a separate class? lutaml-model serialization calls
public_send(attr_name) during to_format, which invokes the
getter method. Entity's field DSL getters read from @properties
and return domain objects (IRDI, source-language String, parsed
Array). The YAML attrs need flat types (String, Hash, Array).
Sharing the same name would make the getter return the wrong
type for serialization. Keeping the YAML model here avoids that
conflict while keeping the adapter "inside" Entity.
Canonical YAML shape:
---
irdi: 0112/2///61360_4#AAA001
type: class
code: AAA001
preferred_name:
en: Vehicle
fr: Véhicule
class_type: ITEM_CLASS
superclass: 0112/2///61360_4#AAA000
applicable_properties:
- 0112/2///61360_4#AAAP001
extra:
C016: released
Constant Summary collapse
- SKIP_FIELDS =
Fields that should NOT be driven from FieldRegistry in from_entity — they're either identity fields (irdi, code) or catch-all (extra, raw_properties, version_history, etc.) handled separately.
%i[ raw_properties version_history dates source_document_of_definition synonymous_names simplified_drawing example time_stamp status_level publisher published_in responsible_committee change_request_id data_object_identifier alternative_unit_irdis domain_of_function_irdis formula_language external_solver trigger_event domain_element_type codomain_element_type role segment super_relation_irdi sgml_representation unit_sgml class_value_assignment coded_name symbol_in_text constraint type_classification applicable_documents imported_documents superclass_type_property ].freeze
- KNOWN_WIRE_IDS =
%w[ MDC_P002_1 MDC_P002_2 MDC_P066 MDC_P004 MDC_P005 MDC_P006 MDC_P008 MDC_P009 MDC_P112 MDC_P011 MDC_P010 MDC_P010_1 MDC_P013 MDC_P014 MDC_P090 MDC_P016 MDC_P022 MDC_P024 MDC_P021 MDC_P041 MDC_P028 MDC_P020 MDC_P023 MDC_P023_1 MDC_P023_2 MDC_P046 MDC_P044 MDC_P043 MDC_P200 MDC_P203 MDC_P204 EXT_P002 EXT_P003 ].freeze
Class Method Summary collapse
-
.attribute_names ⇒ Object
Returns the list of declared lutaml-model attribute names.
- .field_to_yaml(value, field) ⇒ Object
-
.from_entity(entity) ⇒ Object
── Conversion: Entity → Entity::Yaml ─────────────────── Drives from FieldRegistry — the same SSOT that drives the JSON exporter.
- .merge_ml(props, pid, hash) ⇒ Object
-
.read_field_for_yaml(entity, field) ⇒ Object
── FieldRegistry-driven value conversion ─────────────── For multilingual fields, returns the full Hash<lang,text> by scanning @properties for <property_id>.
keys.
Instance Method Summary collapse
-
#to_entity(_database = nil) ⇒ Object
── Conversion: Entity::Yaml → Entity ───────────────────.
Class Method Details
.attribute_names ⇒ Object
Returns the list of declared lutaml-model attribute names. Used by from_entity to check if a field's wire_name matches a declared YAML attribute.
313 314 315 |
# File 'lib/opencdd/entity/yaml.rb', line 313 def self.attribute_names attributes.map { |name, _| name.to_s } end |
.field_to_yaml(value, field) ⇒ Object
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/opencdd/entity/yaml.rb', line 285 def self.field_to_yaml(value, field) case field.value_kind when :synonym_pairs return nil if value.nil? value.transform_keys(&:to_s) when :irdi, :identifier_ref, :class_ref value&.to_s when :set_of_refs, :string_list return nil if value.nil? || value.empty? value.map(&:to_s) when :string, :date, :date_time, :condition value&.to_s when :integer value when :boolean value else case value when Array then value.empty? ? nil : value.map(&:to_s) when Hash then value.empty? ? nil : value else value.to_s end end end |
.from_entity(entity) ⇒ Object
── Conversion: Entity → Entity::Yaml ───────────────────
Drives from FieldRegistry — the same SSOT that drives the
JSON exporter. Each field's wire_name (from the as: DSL
option) determines the YAML attribute to set. Adding a new
field requires zero changes here if the wire_name matches
a declared YAML attribute.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/opencdd/entity/yaml.rb', line 125 def self.from_entity(entity) attrs = { irdi: entity.irdi&.to_s, type: entity.type&.to_s, code: entity.code, } declared_attrs = attribute_names seen_property_ids = {} Opencdd::Entity::FieldRegistry.fields_for(entity.class).each do |field| next if SKIP_FIELDS.include?(field.name) next unless declared_attrs.include?(field.wire_name) next if field.property_id && seen_property_ids.key?(field.property_id) seen_property_ids[field.property_id] = true if field.property_id value = read_field_for_yaml(entity, field) next if value.nil? attrs[field.wire_name.to_sym] = value end extra = extract_extra(entity) attrs[:extra] = extra if extra new(**attrs.compact) end |
.merge_ml(props, pid, hash) ⇒ Object
255 256 257 258 |
# File 'lib/opencdd/entity/yaml.rb', line 255 def self.merge_ml(props, pid, hash) return unless hash&.any? hash.each { |lang, val| props["#{pid}.#{lang}"] = val } end |
.read_field_for_yaml(entity, field) ⇒ Object
── FieldRegistry-driven value conversion ───────────────
For multilingual fields, returns the full Hash<lang,text>
by scanning @properties for <property_id>.
275 276 277 278 279 280 281 282 283 |
# File 'lib/opencdd/entity/yaml.rb', line 275 def self.read_field_for_yaml(entity, field) if field.multilingual? && field.property_id extract_ml(entity, field.property_id) else value = entity.read_field(field.name) return nil if value.nil? field_to_yaml(value, field) end end |
Instance Method Details
#to_entity(_database = nil) ⇒ Object
── Conversion: Entity::Yaml → Entity ───────────────────
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/opencdd/entity/yaml.rb', line 154 def to_entity(_database = nil) props = {} props[Opencdd::PropertyIds::MDC_P066] = guid if guid props[Opencdd::PropertyIds::MDC_P002_1] = version if version props[Opencdd::PropertyIds::MDC_P002_2] = revision if revision merge_ml_into(props, Opencdd::PropertyIds::MDC_P004, preferred_name) merge_ml_into(props, Opencdd::PropertyIds::MDC_P005, short_name) merge_ml_into(props, Opencdd::PropertyIds::MDC_P006, definition) merge_ml_into(props, Opencdd::PropertyIds::MDC_P008, note) merge_ml_into(props, Opencdd::PropertyIds::MDC_P009, remark) merge_ml_into(props, Opencdd::PropertyIds::MDC_P112, description) props[Opencdd::PropertyIds::MDC_P011] = class_type if class_type props[Opencdd::PropertyIds::MDC_P010] = superclass if superclass props[Opencdd::PropertyIds::MDC_P013] = rejoin_set(is_case_of) if is_case_of&.any? props[Opencdd::PropertyIds::MDC_P014] = rejoin_set(applicable_properties) if applicable_properties&.any? props[Opencdd::PropertyIds::MDC_P090] = rejoin_set(imported_properties) if imported_properties&.any? props[Opencdd::PropertyIds::MDC_P016] = rejoin_set(sub_class_selection) if sub_class_selection&.any? props[Opencdd::PropertyIds::MDC_P022] = data_type if data_type props[Opencdd::PropertyIds::MDC_P024] = value_format if value_format props[Opencdd::PropertyIds::MDC_P021] = definition_class if definition_class props[Opencdd::PropertyIds::MDC_P041] = unit if unit props[Opencdd::PropertyIds::MDC_P028] = condition if condition props[Opencdd::PropertyIds::MDC_P020] = property_data_element_type if property_data_element_type props[Opencdd::PropertyIds::MDC_P023] = unit_structure if unit_structure props[Opencdd::PropertyIds::MDC_P023_1] = unit_text if unit_text props[Opencdd::PropertyIds::MDC_P046] = list_type if list_type props[Opencdd::PropertyIds::MDC_P043] = rejoin_set(term_irdis) if term_irdis&.any? # MDC_P044 is overloaded: code_list (value_list, collection) # vs enumeration_code (value_term, scalar). Guard by type to # prevent the value_term path from clobbering the value_list. case type&.to_sym when :value_list props[Opencdd::PropertyIds::MDC_P044] = rejoin_set(code_list) if code_list&.any? when :value_term props[Opencdd::PropertyIds::MDC_P044] = enumeration_code if enumeration_code end props[Opencdd::PropertyIds::MDC_P200] = relation_type if relation_type props[Opencdd::PropertyIds::MDC_P203] = codomain if codomain props[Opencdd::PropertyIds::MDC_P204] = formula if formula props[Opencdd::PropertyIds::EXT_P002] = rejoin_set(controlled_classes) if controlled_classes&.any? props[Opencdd::PropertyIds::EXT_P003] = rejoin_set(shown_properties) if shown_properties&.any? extra&.each { |k, v| props[k.to_s] = v } entity_class = Opencdd::MetaClasses.entity_class_for_type(type&.to_sym) || Opencdd::Klass = Opencdd::MetaClasses.(type&.to_sym) || Opencdd::MetaClasses::MDC_C002 entity_class.new( irdi: irdi ? Opencdd::IRDI.parse(irdi) : nil, properties: props, meta_class_irdi: Opencdd::IRDI.parse(), ) end |