module
Sepia::Container
Overview
Module for objects that contain other Sepia objects.
The Container module enables objects to contain nested Serializable or
Container objects. Containers serialize as directories on disk, with
contained objects stored as files, subdirectories, or symlinks.
⚠️ WARNING: The Container API and on-disk format are subject to change. Data migrations will be required when upgrading Sepia versions.
Key Features
- Automatic JSON Serialization: Primitive properties are automatically
serialized to a
data.jsonfile - Nested Object Storage: Contained Sepia objects are stored as references
- Complex Structure Support: Handles Arrays, Hashes, Sets, and nilable references
- Symlink References: Serializable objects are stored as symlinks to avoid duplication
Directory Structure
container_id/
├── data.json # Primitive properties (automatic)
├── simple_array/ # Array of primitives
│ ├── 0000_value1
│ └── 0001_value2
├── object_array/ # Array of Sepia objects
│ ├── 0000 -> ../../ClassName/id1
│ └── 0001 -> ../../ClassName/id2
├── nested_object/ # Single Sepia object
│ └── 0000 -> ../../OtherClass/id
└── complex_hash/ # Hash with mixed types
├── key1/value1 # Primitive value
└── key2 -> ../../RefClass/id # Sepia object reference
Example
class Project < Sepia::Object
include Sepia::Container
# Primitive properties - automatically serialized
property name : String
property created_at : Time
property tags : Array(String)
# Sepia object references - stored as symlinks
owner : User?
tasks : Array(Task)
metadata : Hash(String, Document)?
def initialize(@name = "")
@created_at = Time.utc
@tags = [] of String
@tasks = [] of Task
end
end
project = Project.new("My Project")
project.owner = user # User object
project.tasks << task1 << task2 # Task objects
project.save # Creates directory structure
Defined in:
sepia/container.crInstance Method Summary
-
#load_enumerable_of_containers(path : String, name : String, collection_type : T.class, item_type : U.class) forall T, U
Loads an enumerable of containers from a directory of subdirectories.
-
#load_enumerable_of_references(path : String, name : String, collection_type : T.class, item_type : U.class) forall T, U
Loads an enumerable of serializable objects from a directory of symlinks.
-
#load_hash_of_containers(path : String, name : String, collection_type : T.class, item_type : U.class) forall T, U
Loads a hash of containers from a directory of subdirectories.
-
#load_hash_of_references(path : String, name : String, collection_type : T.class, item_type : U.class) forall T, U
Loads a hash of serializable objects from a directory of symlinks.
-
#load_references(path : String)
Loads all references (Serializable, Container, Enumerable of either) from the container's path.
-
#log_activity(action : String, metadata)
Logs an activity event for this container.
-
#log_activity(action : String)
Logs an activity event for this object (without metadata).
-
#restore_properties_from_json(json_data : String)
Restore primitive properties from JSON without creating a new instance
-
#save_references(path : String)
Saves all references (Serializable, Container, Enumerable of either) to the container's path.
-
#sepia_references : Enumerable(Sepia::Object)
Returns all Sepia objects referenced by this container.
-
#to_filtered_json : String
Serializes only primitive properties to JSON.
Instance Method Detail
Loads an enumerable of containers from a directory of subdirectories.
Loads an enumerable of serializable objects from a directory of symlinks.
Loads a hash of containers from a directory of subdirectories.
Loads a hash of serializable objects from a directory of symlinks.
Loads all references (Serializable, Container, Enumerable of either) from the container's path.
Logs an activity event for this container.
This method allows containers to log arbitrary activities that are not related to object persistence (save/delete operations). Activities are stored in the container's event log alongside other events.
Parameters
- action : Description of the activity (e.g., "moved_lane", "edited")
- metadata : Optional metadata for the activity (caller's responsibility for JSON serializability)
Example
board.log_activity("lane_created", {"lane_name" => "Review", "user" => "alice"})
# Simple version
board.log_activity("color_changed")
Logs an activity event for this object (without metadata).
This method allows objects to log arbitrary activities that are not related to object persistence (save/delete operations). Activities are stored in the object's event log alongside other events.
Parameters
- action : Description of the activity (e.g., "moved_lane", "edited")
Example
board.log_activity("color_changed")
Restore primitive properties from JSON without creating a new instance
Saves all references (Serializable, Container, Enumerable of either) to the container's path.
Returns all Sepia objects referenced by this container.
This method automatically inspects all instance variables and collects any Sepia objects, including those nested in Arrays, Hashes, and Sets. Used by the garbage collector to track object relationships.
Returns
An Enumerable containing all Sepia objects referenced by this container.
Example
class Team < Sepia::Object
include Sepia::Container
property members : Array(User)
property lead : User?
property projects : Hash(String, Project)
def initialize
@members = [] of User
@projects = {} of String => Project
end
end
team = Team.new
team.members << user1 << user2
team.lead = user3
team.projects["web"] = project1
refs = team.sepia_references
# refs contains [user1, user2, user3, project1]
Serializes only primitive properties to JSON.
This method automatically filters out any Sepia object references,
serializing only primitive types (String, Int32, Bool, Time, etc.)
and collections of primitives. The resulting JSON is stored in
the container's data.json file.
Returns
A JSON string containing only the primitive properties of the container.
Example
class UserProfile < Sepia::Object
include Sepia::Container
property name : String # Included in JSON
property age : Int32 # Included in JSON
property friends : Array(User) # Excluded (Sepia objects)
def initialize(@name = "", @age = 0)
@friends = [] of User
end
end
profile = UserProfile.new("Alice", 30)
json = profile.to_filtered_json
# json = {"name":"Alice","age":30,"friends":[]}