<?xml version="1.0" encoding="UTF-8"?>
<metanorma xmlns="https://www.metanorma.org/ns/standoc" type="semantic" version="2.6.5" schema-version="v2.0.4" flavor="ribose">
<bibdata type="standard">
<title language="en" format="text/plain">LutaML — Model Register</title>
<docidentifier primary="true" type="Ribose">RS 3004</docidentifier><docnumber>RS 3004</docnumber><date type="published"><on>2025-02-20</on></date><contributor><role type="author"/><organization>
<name>Ribose Inc.</name>
<address><formattedAddress>167-169 Great Portland Street<br/>5th Floor<br/>London<br/>W1W 5PF<br/>United Kingdom</formattedAddress></address></organization></contributor><contributor><role type="author"/><person>
<name><completename>Ronald Tse</completename></name>
<affiliation><organization>
<name>Ribose</name>
</organization></affiliation></person></contributor><contributor><role type="publisher"/><organization>
<name>Ribose Inc.</name>
<address><formattedAddress>167-169 Great Portland Street<br/>5th Floor<br/>London<br/>W1W 5PF<br/>United Kingdom</formattedAddress></address></organization></contributor><edition>1.0</edition><language>en</language><script>Latn</script><status><stage>published</stage></status><copyright><from>2025</from><owner><organization>
<name>Ribose Inc.</name>
<address><formattedAddress>167-169 Great Portland Street<br/>5th Floor<br/>London<br/>W1W 5PF<br/>United Kingdom</formattedAddress></address></organization></owner></copyright><ext><doctype>standard</doctype><flavor>ribose</flavor><editorialgroup><committee type="technical">LutaML</committee></editorialgroup><security>unrestricted</security></ext></bibdata><metanorma-extension><presentation-metadata><name>TOC Heading Levels</name><value>2</value></presentation-metadata><presentation-metadata><name>HTML TOC Heading Levels</name><value>2</value></presentation-metadata><presentation-metadata><name>DOC TOC Heading Levels</name><value>2</value></presentation-metadata><presentation-metadata><name>PDF TOC Heading Levels</name><value>2</value></presentation-metadata></metanorma-extension>
<boilerplate><copyright-statement>

<clause id="_e6d5240d-324b-88ca-a190-956ea435c32e" obligation="normative">
<p id="_96cc8bbb-9d9a-ff6c-98e9-9a7a9b0a5def">© Ribose Inc. 2025</p>
</clause>
</copyright-statement>

<legal-statement>

<clause id="_7c9b34cc-5853-55f8-f0b6-1d5149135a25" obligation="normative">
<p id="_50bbfa02-61c3-8332-bad8-61e7389d1808">All rights reserved. Unless otherwise specified, no part of this publication may be reproduced or utilized otherwise in any form or by any means, electronic or mechanical, including photocopying, or posting on the internet or an intranet, without prior written permission. Permission can be requested from the address below.</p>
</clause>
</legal-statement>

<feedback-statement>

<clause id="_836ec555-8fe8-ed0b-96d7-ba7230d4cfaa" obligation="normative">
<p id="boilerplate-name" align="left">Ribose Inc.</p>

<p id="boilerplate-address" align="left">167-169 Great Portland Street<br/>5th Floor<br/>London<br/>W1W 5PF<br/>United Kingdom<br/><br/><link target="mailto:copyright@ribose.com"/><br/><link target="https://www.ribose.com">www.ribose.com</link></p>
</clause>
</feedback-statement>
</boilerplate><sections><clause id="_scope" type="scope" obligation="normative">
<title>Scope</title>
<p id="_3e2f4c9e-dcb1-bdd7-455a-939aec2c4e6c">This document specifies the model register capabilities in LutaML Model, which enable:</p>

<ul id="_57a1f155-15ed-6441-f392-94af67199139"><li><p id="_58394dec-1ae3-343c-a5a6-0d41fadffcb2">Dynamic model attribute modification</p>
</li>
<li><p id="_a26402c1-23e1-2658-c0aa-400dcd949958">Model hierarchy manipulation</p>
</li>
<li><p id="_f1e50537-736f-c1bc-bb8a-45ddafea83b3">Cross-model attribute type substitution</p>
</li>
</ul>
</clause>



<terms id="_terms_and_definitions" obligation="normative">
<title>Terms and definitions</title><p id="_1fbc7bf1-a8de-c3eb-ee88-3b4cf950e61b">For the purposes of this document, the following terms and definitions apply.</p>

<term id="term-model-register"><preferred><expression>
<name>model register</name>
</expression>
</preferred>
<definition><verbal-definition><p id="_8644e20d-87f9-9786-d290-bb41d8fa3abc">registry that maintains and manages dynamic model configurations</p></verbal-definition></definition>
 </term>

<term id="term-model-path"><preferred><expression>
<name>model path</name>
</expression>
</preferred>
<definition><verbal-definition><p id="_7bcd4c4f-6d3a-8c49-ff51-a36dca228090">path expression that identifies a specific model or attribute within a model hierarchy</p></verbal-definition></definition>
 </term>

<term id="term-model-hierarchy"><preferred><expression>
<name>model hierarchy</name>
</expression>
</preferred>
<definition><verbal-definition><p id="_144960ce-7e1d-aca4-76ac-1e0a2fa27145">tree structure that represents the relationships between different models and their attributes</p></verbal-definition></definition>
 </term>

<term id="term-attribute-substitution"><preferred><expression>
<name>attribute substitution</name>
</expression>
</preferred>
<definition><verbal-definition><p id="_4f25fb7d-16af-daba-71e2-a0c082662e93">process of replacing one attribute type with another within a model</p></verbal-definition></definition>
 </term>

<term id="term-model-tree"><preferred><expression>
<name>model tree</name>
</expression>
</preferred>
<definition><verbal-definition><p id="_ea74dd11-826a-d836-1d99-df221935b214">collection of interconnected models that form a hierarchical structure</p></verbal-definition></definition>
 </term>
</terms>

<clause id="_principles_of_model_registers" obligation="normative">
<title>Principles of model registers</title>
<clause id="_general" obligation="normative">
<title>General</title>
<p id="_72aaf52b-c64e-b116-d4e1-433a30732641">A LutaML model register provides a way to dynamically modify and reconfigure model hierarchies without changing the original model definitions.</p>

<p id="_ecb9ccc5-df2a-1d74-ccc5-a64f35df0db9">Common use cases include:</p>

<ul id="_4bc73174-f483-9474-cc10-335e41476fd7"><li><p id="_fbf615f3-0366-5295-7431-40c3ca1fdd15">Replacing attribute types in models</p>
</li>
<li><p id="_e6a03c3e-7f55-a92b-33c3-a2b315c8119c">Swapping model subtrees with alternative implementations</p>
</li>
<li><p id="_cf77c8f6-be36-343f-5cd5-7e30b3d040b2">Adding or removing attributes from models</p>
</li>
<li><p id="_e5a77c3f-7feb-5ef5-4f21-4400baeaf819">Converting between different model namespaces</p>
</li>
</ul>
</clause>

<clause id="_architecture" obligation="normative">
<title>Architecture</title>
<p id="_99f25971-a71d-742b-b8d2-0b50707fc350">A model register acts as a dynamic configuration layer that sits above the static model definitions:</p>

<sourcecode id="_7a142f10-7415-9223-42c3-1c88d3e83188"><body>╔═══════════════════════╗   ╔══════════════════════╗
║    Model Register     ║   ║  Model Definitions   ║
╚═══════════════════════╝   ╚══════════════════════╝
     │                                 │
     │                         ┌───────┴───────┐
     │                         │               │
     │                    Model Tree A    Model Tree B
     │                         │               │
     │                    ┌────┴────┐     ┌────┴────┐
     │                    │         │     │         │
     └────────────────► ModelA  ModelB   ModelC  ModelD</body></sourcecode>


<sourcecode id="_d8975c4b-ba21-f451-960f-48a39b848b21"><name>Subtree Swap</name><body>Before:                        After:
  ModelA                        ModelA
  ├─ModelB                      ├─ModelB
  │ └─ModelC                    │ └─NewSubtree
  └─ModelD                      └─ModelD</body></sourcecode>


<sourcecode id="_75c75683-e6d6-1280-7d15-ffa0e248ec06"><name>Single Model Swap</name><body>Before:                        After:
  ModelA                        ModelA
  ├─ModelB                      ├─NewModel
  └─ModelC                      └─ModelC</body></sourcecode>


<sourcecode id="_8940f32b-bc65-eca2-ffcf-9a657b8dcec7"><name>Global Type Substitution</name><body>Before:                        After:
  Document                      Document
  ├─NameString                  ├─StructuredName
  └─Author                      └─Author
    └─NameString                  └─StructuredName</body></sourcecode>

</clause>

<clause id="_basic_usage" obligation="normative">
<title>Basic usage</title>
<p id="_737723fa-2f00-e7f1-5dc8-712f5c77897a">A model register is created and populated with model definitions:</p>

<sourcecode id="_ca62e622-bf73-2275-703d-69df3880be70" lang="ruby"><body>class StorageRecordCollection &lt; Lutaml::ModelCollection
  instances :items, StorageRecord
end

class StorageRecord
  attribute :ceramic_info, GeneralCeramicInfo
end

class GeneralCeramicInfo &lt; Lutaml::Model::Serializable
  attribute :material, :string
  attribute :production_date, :date
end

register = Lutaml::ModelRegister.new
register.register_model_tree(StorageRecordCollection)</body></sourcecode>

</clause>

<clause id="_model_paths" obligation="normative">
<title>Model paths</title>
<p id="_65ece31b-6b75-52c7-9a7f-8ae3fe487332">Model paths identify specific locations within a model hierarchy using the LutaML Path syntax.</p>

<p id="_fd8e7887-ca7c-1291-db9d-e89ed597800e">Common path patterns:</p>

<ul id="_e7db9fc0-7c3a-a461-8a68-f199cfd38323"><li><p id="_61708bbc-ec6e-8df8-8127-3cf78f10ecc1">Single model: <tt>ModelName</tt></p>
</li>
<li><p id="_3b4abf78-ecf4-d6f2-4e8d-6012baabcfb3">Nested model: <tt>ParentModel &gt; ChildModel</tt></p>
</li>
<li><p id="_d9081521-6bad-7d8e-44d9-02dbcae0c19e">Model attribute: <tt>Model.attribute</tt></p>
</li>
<li><p id="_c47270bc-2348-28a2-9ee9-c36538849b21">Nested attribute: <tt>ParentModel &gt; ChildModel.attribute</tt></p>
</li>
</ul>

<example id="_92bdbcc5-0f23-d0db-1277-6505cf700e54"><p id="_c9f254f6-9af9-dcde-addf-8829541ca19b">Given this model hierarchy:</p>

<sourcecode id="_2798b609-4a8a-9d0c-e835-aa28a2b167f9" lang="ruby"><body>class Publication
  attribute :metadata, Metadata
end

class Book &lt; Publication
  attribute :chapters, Chapter, collection: true
end

class Metadata
  attribute :title, :string
  attribute :date, :date
end</body></sourcecode>


<p id="_6b778837-3cb7-b642-9a35-6f59b501b019">Valid model paths include:</p>

<ul id="_609d1386-2101-ddab-c7d6-9a4177127cfb"><li><p id="_b106ac78-63b3-95cf-60dc-d18049629ec3"><tt>Publication</tt> — References the Publication model</p>
</li>
<li><p id="_3dc9c262-56a0-893e-d4f3-98c30abe5fdd"><tt>Publication &gt; Book</tt> — References Book as a child of Publication</p>
</li>
<li><p id="_6a0272a5-ebe9-009e-bb80-fbb37755f37a"><tt>Publication.metadata</tt> — References the metadata attribute</p>
</li>
<li><p id="_7f1bc3ca-057b-ffd4-288e-faf5ee530354"><tt>Publication &gt; Book.chapters</tt> — References the chapters collection</p>
</li>
</ul>
</example>
</clause>
</clause>

<clause id="_model_registration" obligation="normative">
<title>Model registration</title>
<clause id="_general_2" obligation="normative">
<title>General</title>
<p id="_1525c2f1-d0b5-a686-414a-6e4382552911">Models must be registered before they can be dynamically modified.</p>
</clause>

<clause id="_registration_methods" obligation="normative">
<title>Registration methods</title>
<clause id="_register_individual_model" obligation="normative">
<title>Register individual model</title>
<p id="_8bf376e3-2c42-f10c-5f44-a5966e68e480">Registers a single model class.</p>

<p id="_131e5ca0-b000-a0e6-cc85-fcd9d2149611">Syntax:</p>

<sourcecode id="_1fb37a6a-a31c-7bff-e7b7-bfb28572afd3" lang="ruby"><body>register.register_model(ModelClass)</body></sourcecode>


<example id="_a42c8547-f724-bb66-ced4-13610e227f2e"><sourcecode id="_ed701d4d-1171-3d89-2bae-f0ebca7e2dd1" lang="ruby"><body>register.register_model(StorageRecord)</body></sourcecode> </example>
</clause>

<clause id="_register_model_tree" obligation="normative">
<title>Register model tree</title>
<p id="_09ab6def-545e-8931-621a-b3ef98c1dba8">Registers a model and all its dependent models.</p>

<p id="_82b3ab13-f1ab-dc3e-58a3-d6f16343a4e3">Syntax:</p>

<sourcecode id="_686cd289-cb4c-eccd-0f89-824cec84feae" lang="ruby"><body>register.register_model_tree(RootModelClass)</body></sourcecode>


<example id="_c5b94197-7434-e53d-9903-d04b644bf5f6"><sourcecode id="_4ec12207-ea94-5203-df5b-38cfd9379308" lang="ruby"><body>register.register_model_tree(StorageRecordCollection)
# Automatically registers:
# - StorageRecordCollection
# - StorageRecord
# - GeneralCeramicInfo</body></sourcecode> </example>
</clause>
</clause>
</clause>

<clause id="_dynamic_modifications" obligation="normative">
<title>Dynamic modifications</title>
<clause id="_attribute_type_substitution" obligation="normative">
<title>Attribute type substitution</title>
<clause id="_general_3" obligation="normative">
<title>General</title>
<p id="_93966c0f-24d1-cb56-6289-8b772dc5c643">Replace an attribute’s type with another model type.</p>
</clause>

<clause id="_single_attribute_substitution" obligation="normative">
<title>Single attribute substitution</title>
<p id="_a807e219-78f0-0fb0-9259-ee7b39bf20f2">Replaces a specific attribute instance’s type.</p>

<p id="_55964d99-125e-5a2e-0b6f-3ad5f8c47883">Syntax:</p>

<sourcecode id="_10cedcda-3283-420f-8563-392b922c5b6a" lang="ruby"><body>register.register_dynamic_attribute(
  model_path: "Model &gt; SubModel.attribute",
  attribute: :attribute_name,
  type: NewAttributeType
)</body></sourcecode>


<example id="_77e18131-3b08-36b1-f891-e234a993a137"><sourcecode id="_1a30b088-0ff8-9657-668a-0080f5baa92a" lang="ruby"><body>class VaseCeramicInfo &lt; GeneralCeramicInfo
  attribute :height, :float
  attribute :diameter, :float
end

register.register_dynamic_attribute(
  model_path: "StorageRecordCollection &gt; StorageRecord",
  attribute: :ceramic_info,
  type: VaseCeramicInfo
)</body></sourcecode> </example>
</clause>

<clause id="_global_type_substitution" obligation="normative">
<title>Global type substitution</title>
<p id="_ef43ec92-4793-da02-d050-a53d6d554baa">Replaces all instances of a type throughout the model hierarchy.</p>

<p id="_506b1e81-6d10-6cf1-3361-56011e94f3a5">Syntax:</p>

<sourcecode id="_4985f6f4-77ff-4adb-17fa-cc65c1caf1a6" lang="ruby"><body>register.register_global_type_substitution(
  from_type: OldType,
  to_type: NewType
)</body></sourcecode>


<example id="_29d45fd5-0e94-d056-0009-07e0c8174fb4"><sourcecode id="_96d842a1-9e57-0b22-9e56-033acdcd79c6" lang="ruby"><body># Replace all Mml::Mi instances with Plurimath equivalents
register.register_global_type_substitution(
  from_type: Mml::Mi,
  to_type: Plurimath::Math::Symbols::Symbol
)</body></sourcecode> </example>
</clause>
</clause>

<clause id="_model_tree_operations" obligation="normative">
<title>Model tree operations</title>
<clause id="_subtree_replacement" obligation="normative">
<title>Subtree replacement</title>
<p id="_23a7dade-9d4b-d88e-ad5c-f97e69374fdd">Replaces an entire subtree in the model hierarchy.</p>

<p id="_66dd893e-6f6f-89d6-3c1e-971745a65d3f">Syntax:</p>

<sourcecode id="_24b57037-9dda-84ce-140a-e0c99955af61" lang="ruby"><body>register.replace_subtree(
  model_path: "Path &gt; To &gt; Subtree",
  new_subtree: NewRootModel
)</body></sourcecode>


<example id="_4e11f0a4-869f-210f-cc53-5a547a5085f8"><sourcecode id="_182419e4-9ddd-502e-7812-9b6d6f9fe9c5" lang="ruby"><body>class NewMetadataTree &lt; Lutaml::Model::Serializable
  attribute :title, :string
  attribute :description, :string
end

register.replace_subtree(
  model_path: "Document &gt; Metadata",
  new_subtree: NewMetadataTree
)</body></sourcecode> </example>
</clause>

<clause id="_attribute_modification" obligation="normative">
<title>Attribute modification</title>
<p id="_d4fa369d-5bb3-433f-3202-9cc9c34b989a">Add or remove attributes from a model.</p>

<p id="_41f81884-4383-1cae-6818-4f5c9d874d2b">Syntax:</p>

<sourcecode id="_a4fc9ee0-3f3a-460e-49a8-53c784016aa2" lang="ruby"><body># Add attribute
register.add_attribute(
  model_path: "Model",
  attribute: :new_attribute,
  type: AttributeType
)

# Remove attribute
register.remove_attribute(
  model_path: "Model",
  attribute: :old_attribute
)</body></sourcecode>


<example id="_a2401516-7603-272b-0189-8db5aacea3d2"><sourcecode id="_c61994bd-df43-bc18-1182-bf1b76d3e723" lang="ruby"><body>register.add_attribute(
  model_path: "StorageRecord",
  attribute: :last_modified,
  type: :datetime
)

register.remove_attribute(
  model_path: "StorageRecord",
  attribute: :deprecated_field
)</body></sourcecode> </example>
</clause>
</clause>

<clause id="_model_resolution" obligation="normative">
<title>Model resolution</title>
<clause id="_general_4" obligation="normative">
<title>General</title>
<p id="_c4126660-5d27-a519-74e7-0ee268ea2712">After configuration, models are retrieved from the register using the resolve method.</p>
</clause>

<clause id="_basic_resolution" obligation="normative">
<title>Basic resolution</title>
<p id="_b20c770c-8e2d-9ce9-abf5-703fce7e2e2f">Retrieves a configured model class by name.</p>

<p id="_50014ade-c14b-c78e-cbe0-5cc3d2c748fe">Syntax:</p>

<sourcecode id="_14b6b092-af43-b5a9-ac79-d6a73f0a351b" lang="ruby"><body>ModelClass = register.resolve("ModelName")</body></sourcecode>


<example id="_fd90f40d-9562-4507-8a6c-2875cdb8318b"><sourcecode id="_11994e3c-cec2-1ee0-7c59-c42f2445a76c" lang="ruby"><body>StorageRecordClass = register.resolve("StorageRecord")
record = StorageRecordClass.new(
  ceramic_info: VaseCeramicInfo.new(
    material: "clay",
    height: 10.0
  )
)</body></sourcecode> </example>
</clause>

<clause id="_path_based_resolution" obligation="normative">
<title>Path-based resolution</title>
<p id="_5321f5df-dec3-28b2-306a-f21034f6286a">Retrieves a model class using a model path.</p>

<p id="_9b89831b-1b81-f3dd-d595-5fd3dae1377c">Syntax:</p>

<sourcecode id="_8625b97b-285f-f985-d306-d16630ea62eb" lang="ruby"><body>ModelClass = register.resolve_path("Path &gt; To &gt; Model")</body></sourcecode>


<example id="_374e0968-94d5-1aba-d0a6-a34b40184d8f"><sourcecode id="_bf3609b2-ef46-f2a1-b29f-b649a28be498" lang="ruby"><body>VaseRecord = register.resolve_path(
  "StorageRecordCollection &gt; StorageRecord"
)</body></sourcecode> </example>
</clause>
</clause>
</clause>

<clause id="_example_scenarios" obligation="normative">
<title>Example scenarios</title>
<clause id="_namespace_conversion" obligation="normative">
<title>Namespace conversion</title>
<p id="_88dd9294-233d-01de-328c-c70f8519291e">This example demonstrates converting models between different namespaces.</p>

<sourcecode id="_522803a0-8f61-21ca-fc2f-68ae18b6dfd3" lang="ruby"><body># Original MathML models
module Mml
  class Expression &lt; Lutaml::Model::Serializable
    attribute :operator, Mi
  end

  class Mi &lt; Lutaml::Model::Serializable
    attribute :value, :string
  end
end

# Target Plurimath models
module Plurimath
  module Math
    module Symbols
      class Symbol &lt; Lutaml::Model::Serializable
        attribute :value, :string
      end
    end
  end
end

# Register and configure conversion
register = Lutaml::ModelRegister.new
register.register_model_tree(Mml::Expression)

register.register_global_type_substitution(
  from_type: Mml::Mi,
  to_type: Plurimath::Math::Symbols::Symbol
)

# Use converted models
ExpressionClass = register.resolve("Mml::Expression")
expression = ExpressionClass.new(
  operator: Plurimath::Math::Symbols::Symbol.new(
    value: "+"
  )
)</body></sourcecode>

</clause>

<clause id="_dynamic_model_extension" obligation="normative">
<title>Dynamic model extension</title>
<p id="_123ae324-925b-7013-ae3c-44007edd1fe5">This example shows extending models with new attributes.</p>

<sourcecode id="_d3e9f206-6c18-9159-063b-471aacafb251" lang="ruby"><body>class BaseDocument &lt; Lutaml::Model::Serializable
  attribute :title, :string
end

class Chapter &lt; Lutaml::Model::Serializable
  attribute :content, :string
end

register = Lutaml::ModelRegister.new
register.register_model_tree(BaseDocument)

# Add versioning attributes
register.add_attribute(
  model_path: "BaseDocument",
  attribute: :version,
  type: :string
)

register.add_attribute(
  model_path: "Chapter",
  attribute: :last_modified,
  type: :datetime
)

# Use extended models
DocumentClass = register.resolve("BaseDocument")
doc = DocumentClass.new(
  title: "Example",
  version: "1.0"
)</body></sourcecode>

</clause>
</clause>


</sections><annex id="_tutorial_building_an_adaptive_document_model" obligation="normative">
<title>Tutorial: Building an adaptive document model</title>
<p id="_eea7ad56-6a58-bae5-2b8d-4ef792530c48">This tutorial demonstrates using model registers to create an adaptive document model system that can be customized for different use cases.</p>

<clause id="_step_1_base_document_model" obligation="normative">
<title>Step 1: Base document model</title>
<ul id="_41f9ce9c-40ca-f56b-99a1-bae4cd5f1a08">
<name>Learning outcomes</name>
<li><p id="_edfef20a-64a0-d53c-ec52-75675d96b7b3">Create initial model hierarchy</p>
</li>
<li><p id="_778eac23-3067-ba0c-6693-6a531ba63e35">Register models</p>
</li>
<li><p id="_a729944d-9449-2d27-c567-227b236880c0">Understand basic model relationships</p>
</li>
</ul>

<sourcecode id="_8db5e775-e906-dec6-a7e3-62268d76b05c" lang="ruby"><body># Define base models
class Document &lt; Lutaml::Model::Serializable
  attribute :metadata, Metadata
  attribute :content, Content
end

class Metadata &lt; Lutaml::Model::Serializable
  attribute :title, :string
  attribute :author, :string
  attribute :date, :date
end

class Content &lt; Lutaml::Model::Serializable
  attribute :sections, Section, collection: true
end

class Section &lt; Lutaml::Model::Serializable
  attribute :title, :string
  attribute :body, :string
end

# Create and populate register
register = Lutaml::ModelRegister.new
register.register_model_tree(Document)</body></sourcecode>

</clause>

<clause id="_step_2_technical_documentation_extension" obligation="normative">
<title>Step 2: Technical documentation extension</title>
<ul id="_810c8209-c5ff-a1d5-89f6-cc408eedeabb">
<name>Learning outcomes</name>
<li><p id="_e12763b2-7685-d6ed-0325-c03edd862f86">Extend models with new attributes</p>
</li>
<li><p id="_82720fce-6d53-d16d-8b16-8a83c1b66fae">Replace attribute types</p>
</li>
<li><p id="_01cfb1af-76ac-e9e6-851b-442ffef646e8">Use path-based modifications</p>
</li>
</ul>

<sourcecode id="_05d2ee9d-0a96-132b-57fd-4c7dde8dd1d5" lang="ruby"><body># Define technical documentation models
class TechnicalMetadata &lt; Metadata
  attribute :version, :string
  attribute :status, :string
end

class CodeSection &lt; Section
  attribute :language, :string
  attribute :code, :string
end

# Configure register
register.register_dynamic_attribute(
  model_path: "Document",
  attribute: :metadata,
  type: TechnicalMetadata
)

register.add_attribute(
  model_path: "Document &gt; Content &gt; Section",
  attribute: :type,
  type: :string
)

# Allow code sections
register.register_dynamic_attribute(
  model_path: "Document &gt; Content",
  attribute: :sections,
  type: CodeSection
)</body></sourcecode>

</clause>

<clause id="_step_3_academic_publication_extension" obligation="normative">
<title>Step 3: Academic publication extension</title>
<ul id="_570600ec-f4e5-8f25-adbc-535f67c04a3b">
<name>Learning outcomes</name>
<li><p id="_916fc5ad-a8f9-cb35-43f1-a4dd6a49048e">Replace model subtrees</p>
</li>
<li><p id="_5d473c59-e36e-503c-fd0b-505d6ddbb392">Add nested attributes</p>
</li>
<li><p id="_85843bfa-7737-6b67-5f95-5f86d7289b57">Handle collections</p>
</li>
</ul>

<sourcecode id="_154c0b7b-58ff-5768-8d29-889c6dcecfcb" lang="ruby"><body># Define academic models
class AcademicMetadata &lt; Metadata
  attribute :abstract, :string
  attribute :keywords, :string, collection: true
  attribute :references, Reference, collection: true
end

class Reference &lt; Lutaml::Model::Serializable
  attribute :authors, :string, collection: true
  attribute :title, :string
  attribute :journal, :string
  attribute :year, :integer
end

# Configure register
register.replace_subtree(
  model_path: "Document &gt; Metadata",
  new_subtree: AcademicMetadata
)

# Add citation support
register.add_attribute(
  model_path: "Document &gt; Content &gt; Section",
  attribute: :citations,
  type: Reference,
  collection: true
)</body></sourcecode>

</clause>

<clause id="_step_4_global_modifications" obligation="normative">
<title>Step 4: Global modifications</title>
<ul id="_9285acbe-3216-9a5b-8e76-0c0f3902b8c6">
<name>Learning outcomes</name>
<li><p id="_dece2c38-dc35-8357-5c85-ff82965205b5">Apply global type substitutions</p>
</li>
<li><p id="_18d5448c-6f6a-fe86-f772-1c18ea037744">Manage cross-cutting concerns</p>
</li>
<li><p id="_c6ac9cef-efde-d0bb-5f37-af824110ed2a">Handle model relationships</p>
</li>
</ul>

<sourcecode id="_2ace6e33-3525-2ada-0b8e-3118b806757c" lang="ruby"><body># Define enhanced types
class EnhancedString &lt; Lutaml::Model::Serializable
  attribute :value, :string
  attribute :language, :string
  attribute :format, :string
end

# Replace all string attributes with enhanced strings
register.register_global_type_substitution(
  from_type: :string,
  to_type: EnhancedString
)

# Add tracking to all models
register.add_attribute(
  model_path: "*",
  attribute: :created_at,
  type: :datetime
)

register.add_attribute(
  model_path: "*",
  attribute: :updated_at,
  type: :datetime
)</body></sourcecode>

</clause>

<clause id="_summary" obligation="normative">
<title>Summary</title>
<p id="_68b0b737-ced8-7027-e963-9a0ff9b8e2d0">This tutorial demonstrated:</p>

<ul id="_366d457a-ae0c-c1d7-e58f-28b5d5d02ca2"><li><p id="_8662e2f7-36d6-5122-e146-eb2f312515b9">Basic model registration and configuration</p>
</li>
<li><p id="_44f603e3-77f3-6f1a-a7a1-ca60fba9e249">Dynamic attribute type substitution</p>
</li>
<li><p id="_c754476b-fb62-ffb9-4dc4-8aa8f9eaf563">Model subtree replacement</p>
</li>
<li><p id="_1b0e54d3-f5a6-3487-4fdf-23fe7eb7a75f">Global type modifications</p>
</li>
<li><p id="_169987ee-6714-cb5b-b6ad-041bd84504f4">Cross-cutting attribute addition</p>
</li>
</ul>

<p id="_e1d3f55b-67b0-5c14-d0f4-4d198c3046c1">The progression shows how model registers enable flexible and maintainable model configurations that can adapt to different requirements while maintaining model consistency.</p>
</clause>
</annex><bibliography><references id="_normative_references" normative="true" obligation="informative">
<title>Normative references</title><p id="_cf4fafa1-7328-7d25-f309-bb194339feef">There are no normative references in this document.</p>

</references></bibliography>
</metanorma>
