1. Scope
This document specifies the model register capabilities in LutaML Model, which enable:
Dynamic model attribute modification
Model hierarchy manipulation
Cross-model attribute type substitution
3. Terms and definitions
For the purposes of this document, the following terms and definitions apply.
3.1. model register
registry that maintains and manages dynamic model configurations
3.2. model path
path expression that identifies a specific model or attribute within a model hierarchy
3.3. model hierarchy
tree structure that represents the relationships between different models and their attributes
3.4. attribute substitution
process of replacing one attribute type with another within a model
3.5. model tree
collection of interconnected models that form a hierarchical structure
4. Principles of model registers
4.1. General
A LutaML model register provides a way to dynamically modify and reconfigure model hierarchies without changing the original model definitions.
Common use cases include:
Replacing attribute types in models
Swapping model subtrees with alternative implementations
Adding or removing attributes from models
Converting between different model namespaces
4.2. Architecture
A model register acts as a dynamic configuration layer that sits above the static model definitions:
╔═══════════════════════╗ ╔══════════════════════╗
║ Model Register ║ ║ Model Definitions ║
╚═══════════════════════╝ ╚══════════════════════╝
│ │
│ ┌───────┴───────┐
│ │ │
│ Model Tree A Model Tree B
│ │ │
│ ┌────┴────┐ ┌────┴────┐
│ │ │ │ │
└────────────────► ModelA ModelB ModelC ModelD
Figure 1
Before: After:
ModelA ModelA
├─ModelB ├─ModelB
│ └─ModelC │ └─NewSubtree
└─ModelD └─ModelD
Figure 2 — Subtree Swap
Before: After:
ModelA ModelA
├─ModelB ├─NewModel
└─ModelC └─ModelC
Figure 3 — Single Model Swap
Before: After:
Document Document
├─NameString ├─StructuredName
└─Author └─Author
└─NameString └─StructuredName
Figure 4 — Global Type Substitution
4.3. Basic usage
A model register is created and populated with model definitions:
class StorageRecordCollection < Lutaml::ModelCollection
instances :items, StorageRecord
end
class StorageRecord
attribute :ceramic_info, GeneralCeramicInfo
end
class GeneralCeramicInfo < Lutaml::Model::Serializable
attribute :material, :string
attribute :production_date, :date
end
register = Lutaml::ModelRegister.new
register.register_model_tree(StorageRecordCollection)
Figure 5
4.4. Model paths
Model paths identify specific locations within a model hierarchy using the LutaML Path syntax.
Common path patterns:
Single model: ModelName
Nested model: ParentModel > ChildModel
Model attribute: Model.attribute
Nested attribute: ParentModel > ChildModel.attribute
EXAMPLE
Given this model hierarchy:
class Publication
attribute :metadata, Metadata
end
class Book < Publication
attribute :chapters, Chapter, collection: true
end
class Metadata
attribute :title, :string
attribute :date, :date
end
Valid model paths include:
Publication — References the Publication model
Publication > Book — References Book as a child of Publication
Publication.metadata — References the metadata attribute
Publication > Book.chapters — References the chapters collection
5. Model registration
5.1. General
Models must be registered before they can be dynamically modified.
5.2. Registration methods
5.2.1. Register individual model
Registers a single model class.
Syntax:
register.register_model(ModelClass)
Figure 6
EXAMPLE
register.register_model(StorageRecord)
5.2.2. Register model tree
Registers a model and all its dependent models.
Syntax:
register.register_model_tree(RootModelClass)
Figure 7
EXAMPLE
register.register_model_tree(StorageRecordCollection)
# Automatically registers:
# - StorageRecordCollection
# - StorageRecord
# - GeneralCeramicInfo
6. Dynamic modifications
6.1. Attribute type substitution
6.1.1. General
Replace an attribute’s type with another model type.
6.1.2. Single attribute substitution
Replaces a specific attribute instance’s type.
Syntax:
register.register_dynamic_attribute(
model_path: "Model > SubModel.attribute",
attribute: :attribute_name,
type: NewAttributeType
)
Figure 8
EXAMPLE
class VaseCeramicInfo < GeneralCeramicInfo
attribute :height, :float
attribute :diameter, :float
end
register.register_dynamic_attribute(
model_path: "StorageRecordCollection > StorageRecord",
attribute: :ceramic_info,
type: VaseCeramicInfo
)
6.1.3. Global type substitution
Replaces all instances of a type throughout the model hierarchy.
Syntax:
register.register_global_type_substitution(
from_type: OldType,
to_type: NewType
)
Figure 9
EXAMPLE
# Replace all Mml::Mi instances with Plurimath equivalents
register.register_global_type_substitution(
from_type: Mml::Mi,
to_type: Plurimath::Math::Symbols::Symbol
)
6.2. Model tree operations
6.2.1. Subtree replacement
Replaces an entire subtree in the model hierarchy.
Syntax:
register.replace_subtree(
model_path: "Path > To > Subtree",
new_subtree: NewRootModel
)
Figure 10
EXAMPLE
class NewMetadataTree < Lutaml::Model::Serializable
attribute :title, :string
attribute :description, :string
end
register.replace_subtree(
model_path: "Document > Metadata",
new_subtree: NewMetadataTree
)
6.2.2. Attribute modification
Add or remove attributes from a model.
Syntax:
# Add attribute
register.add_attribute(
model_path: "Model",
attribute: :new_attribute,
type: AttributeType
)
# Remove attribute
register.remove_attribute(
model_path: "Model",
attribute: :old_attribute
)
Figure 11
EXAMPLE
register.add_attribute(
model_path: "StorageRecord",
attribute: :last_modified,
type: :datetime
)
register.remove_attribute(
model_path: "StorageRecord",
attribute: :deprecated_field
)
6.3. Model resolution
6.3.1. General
After configuration, models are retrieved from the register using the resolve method.
6.3.2. Basic resolution
Retrieves a configured model class by name.
Syntax:
ModelClass = register.resolve("ModelName")
Figure 12
EXAMPLE
StorageRecordClass = register.resolve("StorageRecord")
record = StorageRecordClass.new(
ceramic_info: VaseCeramicInfo.new(
material: "clay",
height: 10.0
)
)
6.3.3. Path-based resolution
Retrieves a model class using a model path.
Syntax:
ModelClass = register.resolve_path("Path > To > Model")
Figure 13
EXAMPLE
VaseRecord = register.resolve_path(
"StorageRecordCollection > StorageRecord"
)
7. Example scenarios
7.1. Namespace conversion
This example demonstrates converting models between different namespaces.
# Original MathML models
module Mml
class Expression < Lutaml::Model::Serializable
attribute :operator, Mi
end
class Mi < Lutaml::Model::Serializable
attribute :value, :string
end
end
# Target Plurimath models
module Plurimath
module Math
module Symbols
class Symbol < 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: "+"
)
)
Figure 14
7.2. Dynamic model extension
This example shows extending models with new attributes.
class BaseDocument < Lutaml::Model::Serializable
attribute :title, :string
end
class Chapter < 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"
)
Figure 15
Annex A
(normative)
Tutorial: Building an adaptive document model
This tutorial demonstrates using model registers to create an adaptive document model system that can be customized for different use cases.
A.1. Step 1: Base document model
Learning outcomes
Create initial model hierarchy
Register models
Understand basic model relationships
# Define base models
class Document < Lutaml::Model::Serializable
attribute :metadata, Metadata
attribute :content, Content
end
class Metadata < Lutaml::Model::Serializable
attribute :title, :string
attribute :author, :string
attribute :date, :date
end
class Content < Lutaml::Model::Serializable
attribute :sections, Section, collection: true
end
class Section < Lutaml::Model::Serializable
attribute :title, :string
attribute :body, :string
end
# Create and populate register
register = Lutaml::ModelRegister.new
register.register_model_tree(Document)
Figure A.1
A.2. Step 2: Technical documentation extension
Learning outcomes
Extend models with new attributes
Replace attribute types
Use path-based modifications
# Define technical documentation models
class TechnicalMetadata < Metadata
attribute :version, :string
attribute :status, :string
end
class CodeSection < 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 > Content > Section",
attribute: :type,
type: :string
)
# Allow code sections
register.register_dynamic_attribute(
model_path: "Document > Content",
attribute: :sections,
type: CodeSection
)
Figure A.2
A.3. Step 3: Academic publication extension
Learning outcomes
Replace model subtrees
Add nested attributes
Handle collections
# Define academic models
class AcademicMetadata < Metadata
attribute :abstract, :string
attribute :keywords, :string, collection: true
attribute :references, Reference, collection: true
end
class Reference < 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 > Metadata",
new_subtree: AcademicMetadata
)
# Add citation support
register.add_attribute(
model_path: "Document > Content > Section",
attribute: :citations,
type: Reference,
collection: true
)
Figure A.3
A.4. Step 4: Global modifications
Learning outcomes
Apply global type substitutions
Manage cross-cutting concerns
Handle model relationships
# Define enhanced types
class EnhancedString < 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
)
Figure A.4
A.5. Summary
This tutorial demonstrated:
Basic model registration and configuration
Dynamic attribute type substitution
Model subtree replacement
Global type modifications
Cross-cutting attribute addition
The progression shows how model registers enable flexible and maintainable model configurations that can adapt to different requirements while maintaining model consistency.