Introduction
Collections represent groups of model instances. This tutorial shows you how to work with collections in Lutaml::Model.
What are collections?
Collections in Lutaml::Model represent arrays of model instances. They can be:
-
Root collections (key-value formats only)
-
Named collections (with a container element/key)
-
Keyed collections (key-value formats, using unique keys)
-
Nested collections (collections within models)
Using collection attributes
The simplest way to work with collections is using the collection: true option on attributes.
Syntax:
attribute :items, Type, collection: trueExample 1. Basic collection attribute
class Studio < Lutaml::Model::Serializable
attribute :name, :string
attribute :potters, :string, collection: true
xml do
root 'studio'
map_element 'name', to: :name
map_element 'potter', to: :potters
end
key_value do
map 'name', to: :name
map 'potters', to: :potters
end
end<studio>
<name>Pottery Studio</name>
<potter>John Doe</potter>
<potter>Jane Smith</potter>
</studio>name: Pottery Studio
potters:
- John Doe
- Jane Smith> studio = Studio.from_xml(xml)
> studio.potters
> # ["John Doe", "Jane Smith"]
> studio.potters.count
> # 2Collection size constraints
You can enforce collection size limits using ranges:
Example 2. Collection with size constraints
class WorkshopClass < Lutaml::Model::Serializable
attribute :title, :string
attribute :students, :string, collection: 1..20 # Min 1, max 20
key_value do
map 'title', to: :title
map 'students', to: :students
end
end
# This works - 2 students
workshop = WorkshopClass.new(
title: "Pottery Basics",
students: ["Alice", "Bob"]
)
# This fails validation - 0 students (minimum is 1)
workshop = WorkshopClass.new(title: "Empty Class", students: [])
workshop.validate!
# => Lutaml::Model::CollectionCountOutOfRangeErrorUsing Collection classes
For more control, create dedicated Collection classes:
Syntax:
class MyCollection < Lutaml::Model::Collection
instances :items, ItemType
endExample 3. Named collection with Collection class
class Potter < Lutaml::Model::Serializable
attribute :name, :string
attribute :specialty, :string
json do
map 'name', to: :name
map 'specialty', to: :specialty
end
end
class PotterCollection < Lutaml::Model::Collection
instances :potters, Potter
json do
root "potters"
map_instances to: :potters
end
end{
"potters": [
{"name": "John", "specialty": "Bowls"},
{"name": "Jane", "specialty": "Vases"}
]
}> collection = PotterCollection.from_json(json)
> collection.count
> # 2
> collection.first.name
> # "John"
> collection.map(&:specialty)
> # ["Bowls", "Vases"]Enumerable methods
Collections implement Ruby’s Enumerable interface:
# Iterate
collection.each { |potter| puts potter.name }
# Filter
experts = collection.select { |p| p.specialty == "Vases" }
# Transform
names = collection.map(&:name)
# Find
john = collection.find { |p| p.name == "John" }
# Count
collection.count # => 2