dry-struct Documentation
repository·main·Indexed 19 days ago
https://github.com/dry-rb/dry-structA Ruby library for defining strict, schema-based, and immutable data structures. Part of the dry-rb ecosystem, it provides a DSL for declaring attributes with type safety via dry-types, supporting nested structs, sum types, and recursive hash conversion. It ensures data integrity through validation during initialization and offers functional error handling via the try method.
What's inside dry-struct
- dry-struct is a library for defining data structures in Ruby. It provides a way to define schemas for objects, ensuring that the data held within them conforms to specific types and constraints. It is part of the dry-rb ecosystem.
What is the difference between dry-struct and virtus?
mainWhile
Dry::Structlooks similar toVirtus, there are key architectural differences:- Immutability:
Dry::Structs do not provide attribute writers and are intended to be used exclusively as immutable "data objects." - Type Handling: Attribute value handling is delegated to standalone
dry-typesobjects. - Hash Handling: Attribute hash handling is provided by standalone hash schemas from
dry-types. - Composition:
Dry::Structclasses "quack" likedry-types, meaning they can be used within hash schemas, as array members, or summed.
- Immutability:
Use Dry::Struct::Sum for sum types of structs
mainThe
Dry::Struct::Sumclass allows you to define a sum type specifically composed of two or moreDry::Structclasses. UnlikeDry::Types::Sum::Constrained, this implementation prioritizes structural matching over coercion. It attempts to match the input against the 'left' type first, and if that fails, it attempts to match against the 'right' type.You can compose these types using the pipe operator (
|).# Example of composing sum types (conceptual based on API) # sum_type = LeftStruct | RightStructInstall and require dry-struct
mainTo use
dry-structin your Ruby project, ensure the gem is installed and require the main entrypoint. This makes theDry::Structnamespace available for defining data structures.require 'dry/struct'Define a Dry::Struct class with the attribute DSL
mainTo define a formal data object, inherit from
Dry::Structand use theattributemethod to declare fields and their types.Dry::Structobjects are immutable data objects; they do not provide attribute writers.Key characteristics:
- Immutability: Attributes are set at initialization and cannot be changed.
- Type Safety: Values are validated against the provided
dry-typesobjects. - Data Objects: Designed to be used exclusively as read-only data containers.
require 'dry-struct' module Types include Dry.Types() end class Book < Dry::Struct attribute :title, Types::String attribute :subtitle, Types::String.optional end book = Book.new( title: 'Web Development with ROM and Roda', subtitle: nil )Resolve duplicate attribute definitions with RepeatedAttributeError
mainIf you attempt to define the same attribute name multiple times within a single
Dry::Structdefinition, aDry::Struct::RepeatedAttributeErroris raised. The error message identifies the conflicting key.Attribute :key_name has already been definedIdentify RecycledStructError during runtime
mainADry::Struct::RecycledStructErroris a::RuntimeErrorthat indicates a reference to a struct class was garbage collected because no alive objects exist. This is an exceptional state that should not occur in a healthy, working application.Handle missing attributes with MissingAttributeError
mainADry::Struct::MissingAttributeErroris raised when attempting to access or interact with an attribute that does not exist on the struct. This error inherits from::KeyErrorand provides the name of the missing attribute and the class it was expected on.Handle schema mismatch with Dry::Struct::Error
mainWhen you initialize aDry::Structwith input that does not conform to the defined schema or constructor types, aDry::Struct::Erroris raised. This error inherits fromDry::Types::CoercionError.Use Dry::Struct::Value for deeply frozen immutable objects
mainInheriting from
Dry::Struct::Valuecreates a struct where the object and all its attributes are deeply frozen upon initialization. This is achieved using theice_ninegem. While standardDry::Structobjects are frozen,Dry::Struct::Valueensures that nested structures or objects assigned to attributes are also frozen, preventing any mutation of the internal state.Note:
Dry::Struct::Valueis currently marked as deprecated in the codebase; users should check for the recommended replacement in thedry-structdeprecation notices.class Location < Dry::Struct::Value attribute :lat, Types::Float attribute :lng, Types::Float end loc1 = Location.new(lat: 1.23, lng: 4.56) loc2 = Location.new(lat: 1.23, lng: 4.56) loc1.frozen? #=> true loc2.frozen? #=> true loc1 == loc2 #=> trueCheck value membership with ===
mainThe
===method checks if a given value matches either theleftor therightside of theDry::Struct::Sumtype.# Returns true if value matches left or right # sum_type === valueInherit attributes from another struct using attributes_from
mainYou can compose structs by importing the schema of an existing
Dry::Structusingattributes_from. This allows you to reuse attribute definitions across different classes or nest them within a block.class Address < Dry::Struct attribute :city, Types::String attribute :country, Types::String end class User < Dry::Struct attribute :name, Types::String attributes_from Address end # Or nested: class User < Dry::Struct attribute :name, Types::String attribute :address do attributes_from Address end end