dry-struct Documentation

repository·main·Indexed 19 days ago

https://github.com/dry-rb/dry-struct

A 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.

Tokens
3.9K
Snippets
20
Records
25
Agent score
62%

What's inside dry-struct

  1. Overview of dry-struct

    main
    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.
  2. What is the difference between dry-struct and virtus?

    main

    While Dry::Struct looks similar to Virtus, 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-types objects.
    • Hash Handling: Attribute hash handling is provided by standalone hash schemas from dry-types.
    • Composition: Dry::Struct classes "quack" like dry-types, meaning they can be used within hash schemas, as array members, or summed.
  3. Use Dry::Struct::Sum for sum types of structs

    main

    The Dry::Struct::Sum class allows you to define a sum type specifically composed of two or more Dry::Struct classes. Unlike Dry::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 | RightStruct
  4. Define a Dry::Struct class with the attribute DSL

    main

    To define a formal data object, inherit from Dry::Struct and use the attribute method to declare fields and their types. Dry::Struct objects 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-types objects.
    • 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
    )
  5. Resolve duplicate attribute definitions with RepeatedAttributeError

    main

    If you attempt to define the same attribute name multiple times within a single Dry::Struct definition, a Dry::Struct::RepeatedAttributeError is raised. The error message identifies the conflicting key.

    Attribute :key_name has already been defined
  6. Identify RecycledStructError during runtime

    main
    A Dry::Struct::RecycledStructError is a ::RuntimeError that 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.
  7. Handle missing attributes with MissingAttributeError

    main
    A Dry::Struct::MissingAttributeError is raised when attempting to access or interact with an attribute that does not exist on the struct. This error inherits from ::KeyError and provides the name of the missing attribute and the class it was expected on.
  8. Use Dry::Struct::Value for deeply frozen immutable objects

    main

    Inheriting from Dry::Struct::Value creates a struct where the object and all its attributes are deeply frozen upon initialization. This is achieved using the ice_nine gem. While standard Dry::Struct objects are frozen, Dry::Struct::Value ensures that nested structures or objects assigned to attributes are also frozen, preventing any mutation of the internal state.

    Note: Dry::Struct::Value is currently marked as deprecated in the codebase; users should check for the recommended replacement in the dry-struct deprecation 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 #=> true
  9. Inherit attributes from another struct using attributes_from

    main

    You can compose structs by importing the schema of an existing Dry::Struct using attributes_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