### Setup super_diff extension Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/extensions.md Setup for using the :super_diff extension: add the super_diff gem to the test group in the Gemfile and load the extension in spec_helper.rb. ```ruby # Gemfile gem 'super_diff', group: :test # spec_helper.rb Dry::Struct.load_extensions(:super_diff) ``` -------------------------------- ### Rendered output example for a struct sum Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/printer.md Shows the expected rendered output shape for a struct sum, where Dry::Types::Printer renders 'Struct::Sum<...>'. The example is illustrative of the output format produced by the visit_struct_sum method. ```ruby CityOrStreet = Test::City | Test::Street # Dry::Types::Printer renders: Struct::Sum<...> ``` -------------------------------- ### attributes(new_schema) usage example with Book class Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Example of defining a struct class with attributes using the `attributes` method. Shows how to create a Book struct with title and author attributes, and demonstrates the resulting schema. ```ruby class Book < Dry::Struct attributes( title: Types::String, author: Types::String ) end Book.schema #=> #>...]> ``` -------------------------------- ### Constructor example with fallback defaults Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/constructor.md Demonstrates a block-form constructor that retries with merged defaults on failure. Shows construction, type, primitive, and optional behavior. ```ruby defaults = {age: 18, name: "John Doe"} type = Test::User.constructor do |input, type| type.(input) { type.(defaults.merge(input)) } end user = type.(address: {city: "London", zipcode: 123_123}) #=> # (built on second try with defaults) user.is_a?(Test::User) #=> true type.type #=> Test::User type.primitive #=> Test::User type.optional.(nil) #=> nil ``` -------------------------------- ### Dry::Struct::ClassInterface#meta - Example usage Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Shows the return value of calling .meta with a hash: the metadata is stored and returned as a hash. ```ruby Test::User.meta(foo: :bar).meta #=> {foo: :bar} ``` -------------------------------- ### Pretty-print output example Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/extensions.md Shows the output shape of the :pretty_print extension. After loading the extension, calling pp on a struct instance produces a grouped representation with each attribute on its own line, including nested structs. ```ruby Dry::Struct.load_extensions(:pretty_print) pp user #=> #> ``` -------------------------------- ### Sum#try behavior examples Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/sum.md Shows the result of try: true for a matching struct instance, false for a hash that doesn't match any member. ```ruby sum.try(Test::City.new(name: "London")).success? #=> true sum.try(name: 123).success? #=> false ``` -------------------------------- ### Direct invocation examples of Hashify.[] Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/hashify.md Shows direct calls to `Dry::Struct::Hashify[]` with various inputs: a struct, an array of structs, an integer (identity), and a nested array (deep map). Demonstrates the recursive conversion behavior. ```ruby Dry::Struct::Hashify[Test::Address.new(city: "NYC", zipcode: "123")] #=> {city: "NYC", zipcode: "123"} Dry::Struct::Hashify[[Test::Address.new(city: "NYC")]] #=> [{city: "NYC"}] Dry::Struct::Hashify[42] #=> 42 (identity) Dry::Struct::Hashify[["a", [1, 2]]] #=> ["a", [1, 2]] (deep map, identity for non-convertibles) ``` -------------------------------- ### Sum#call behavior examples Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/sum.md Demonstrates the behavior of call: struct instances are returned as-is, subclass instances are returned as-is, and hashes are coerced to the first matching member. ```ruby sum = Test::Street | Test::City | Test::Region sum.(Test::City.new(name: "London")) #=> # (as-is) sum.(Test::Highway.new(name: "A1")) #=> as-is (Highway < Street) sum.(name: "Baker") #=> # (first match) ``` -------------------------------- ### Pattern matching with deconstruct_keys Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/struct.md Example of using a struct in a `case ... in` expression with named fields, showing how `deconstruct_keys` enables matching against struct attributes. ```ruby case user in User(first_name:, last_name: "Doe") "DOE, #{first_name.upcase}" end ``` -------------------------------- ### Dry::Struct .constructor usage example Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Shows a typical constructor usage that retries with defaults merged in. The constructor block calls the type with a fallback that merges defaults on the second attempt, demonstrating how to customize construction behavior. ```ruby type = Test::User.constructor do |input, type| type.(input) { type.(defaults.merge(input)) } end type.(address: {city: "London", zipcode: 123_123}) #=> a Test::User (defaults filled on 2nd try) ``` -------------------------------- ### Dry::Struct::ClassInterface#to_ast - Example usage Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Shows the AST representation of a struct class, with the class as a WeakRef target. ```ruby address.to_ast #=> [:struct, [address, address.schema.to_ast]] # `address` here is the WeakRef target ``` -------------------------------- ### Error handling example Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/constructor.md Shows that a failed construction raises Dry::Struct::Error with a message indicating the invalid type for the attribute. ```ruby begin type.(name: "Jane", age: "abc") # fails first try, fallback raises on second rescue Dry::Struct::Error => e e.message #=> '[Test::User.new] "abc" (String) has invalid type for :age' end ``` -------------------------------- ### Usage example: struct.to_h output Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/hashify.md Shows the result of calling `to_h` on a struct with nested structs and arrays, producing a plain hash with nested hashes and arrays. ```ruby struct.to_h #=> { # name: "Jane", # age: 29, # address: {city: "NYC", zipcode: "123"}, # children: [{name: "Joe", age: 3, address: {city: "NYC", zipcode: "123"}}] # } ``` -------------------------------- ### Dry::Struct::ClassInterface#| - Example usage Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Shows how to create a sum type from two struct classes using the | operator. ```ruby CityOrStreet = Test::City | Test::Street ``` -------------------------------- ### Dry::Struct #try usage example Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Shows #try returning a Success result for valid input and a Failure result (or block result) for invalid input. The first call succeeds with a hash, the second demonstrates the error-handling block receiving the failure. ```ruby result = Test::User.try(name: "Jane", age: 21, address: {city: "NYC", zipcode: "1"}) result.success? #=> true Test::User.try({}) { |failure| log(failure); failure } # error-handling path ``` -------------------------------- ### Dry::Struct::ClassInterface#abstract - Example usage Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Shows how to define an abstract struct class and a nested struct that inherits from it. The nested struct's schema is accessible via the abstract class. ```ruby class Test::Abstract < Dry::Struct abstract transform_keys(&:to_sym) def key?(key) attributes.key?(key) end end class Test::User < Test::Abstract attribute :address do attribute :city, "string" end end Test::User::Address < Test::Abstract #=> true; address.key?(:city) #=> true ``` -------------------------------- ### Round-trip compilation examples Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/compiler.md Shows round-trip compilation: a plain struct, a struct with a constructor, and an optional struct all compile back to the same class object. The compiler is instantiated with Dry::Types as the registry. ```ruby compiler = Dry::Struct::Compiler.new(Dry::Types) address = Dry.Struct(street: "string", city?: "optional.string") compiler.(address.to_ast) #=> address (same class object) address = address.constructor(:itself.to_proc) compiler.(address.to_ast) #=> address address = address.optional compiler.(address.to_ast) #=> address ``` -------------------------------- ### .meta Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Type-level operation to get or set metadata on a struct class. ```APIDOC ## `.meta(meta = Undefined)` ### Description Gets or sets metadata on the struct class. When called with no arguments, returns the current metadata hash. When called with an empty hash, returns self. Otherwise, returns a new anonymous subclass carrying the metadata in its schema. ### Method `meta` ### Parameters - `meta` (Hash) - Optional - Default: `Undefined` (dry-core sentinel) - Metadata to store in the schema. ### Returns - No argument → `schema.meta` (the current metadata hash) - Empty hash → `self` - Otherwise → a new anonymous subclass carrying the metadata in its schema. ### Example ```ruby Test::User.meta(foo: :bar).meta #=> {foo: :bar} ``` ``` -------------------------------- ### #initialize(attributes) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/struct.md Initializes a new struct instance with the given attributes hash. This method is not meant to be called directly; use the class constructor `.new` or instance `#new` instead. ```APIDOC ## #initialize(attributes) ### Description Plain assignment of the already-validated hash. Do not call directly — use `.new` (class) or `#new` (instance), or the internal class method `load`. ### Method Constructor ### Endpoint `Dry::Struct#initialize` ### Parameters - `attributes` (Hash, #each) - Required - The attribute hash to assign. ### Returns `Dry::Struct` instance. ### Example ```ruby person = Person.new(name: "Matz", age: 52) ``` ``` -------------------------------- ### Combining sums with | Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/sum.md Shows how to combine sums with | to create a single tree with multiple members. ```ruby (Test::Street | Test::City) | Test::Region # one tree with three members ``` -------------------------------- ### Defining attributes with .attribute and .attribute? Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Shows how to define required and optional attributes on a struct class, and how to instantiate objects with or without the optional key. Also demonstrates the has_attribute? check. ```ruby class User < Dry::Struct attribute :name, Types::String attribute? :email, Types::String end User.new(name: "John") #=> # (no :email key stored) User.new(name: "John", email: "j@x.io") #=> # User.has_attribute?(:email) #=> true ``` -------------------------------- ### Dry::Struct::Value Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/value.md Documentation for the deprecated Dry::Struct::Value class, including its declaration, behavior, usage examples, and error handling. ```APIDOC ## [CLASS] Dry::Struct::Value ### Description `Dry::Struct::Value` is a subclass of `Dry::Struct` that deeply freezes its instances using the `ice_nine` gem. It is deprecated; accessing it emits a deprecation warning. Use plain `Dry::Struct` and apply `ice_nine` manually if deep freezing is needed. ### Declaration ```ruby class Value < self abstract # @param (see ClassInterface#new) # @return [Value] # @see https://github.com/dkubb/ice_nine def self.new(*) = ::IceNine.deep_freeze(super) end deprecate_constant :Value ``` ### Members - **Value class** - `class Value < Struct` - Abstract by default; same attribute DSL as `Dry::Struct`. - **Value.new** - `def self.new(*) = ::IceNine.deep_freeze(super)` - Runs the normal class-level `new` and then deep-freezes the result, including all nested attribute values and collections. ### Returns `Dry::Struct::Value` — a fully frozen instance. ### Behavior - Instances behave as immutable values: the equalizer-based `==` / `eql?` / `hash` (on `__attributes__`) make structurally-equal instances compare equal. - Freezing is deep: nested structs and collections inside attributes are frozen too. - `Value.new(...)` accepts exactly the same arguments as `Dry::Struct.new(...)`, including struct instances (returned as-is) and safe-mode blocks. ### Example ```ruby 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 ``` ### Nested Usage Example ```ruby class User < Dry::Struct::Value attribute :name, "coercible.string" attribute :age, "coercible.integer" attribute :address, Test::Address # Address is also a Dry::Struct::Value end user = User.new(name: "Jane", age: "21", address: {city: "NYC", zipcode: 123}) user.frozen? #=> true user.address.frozen? #=> true user.age #=> 21 (coerced from "21") ``` ### Error Handling Invalid input raises `Dry::Struct::Error`: ```ruby begin Location.new(lat: "not-a-float") rescue Dry::Struct::Error => e e.message #=> '[Location.new] "not-a-float" (String) has invalid type for :lat' end ``` ### Deprecation Accessing `Dry::Struct::Value` emits a deprecation warning (`deprecate_constant :Value`). ``` -------------------------------- ### transform_keys usage with Book struct and string keys Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Demonstrates using `transform_keys(&:to_sym)` to convert string keys to symbols when initializing a struct. Shows that a Book instance can be created with string keys and the transformation converts them. ```ruby class Book < Dry::Struct transform_keys(&:to_sym) attribute :title, Types::String end Book.new("title" => "The Old Man and the Sea") #=> # ``` -------------------------------- ### .constructor(constructor = nil, **, &block) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Creates a constructor wrapper for the struct class, allowing custom construction behavior. ```APIDOC ## `.constructor(constructor = nil, **, &block)` ### Description Wraps the struct class in a `Dry::Struct::Constructor` that allows custom construction logic, such as retrying with defaults merged in. ### Method `.constructor` ### Parameters - `constructor` (#call) - Optional - Function that can wrap/fall back the default construction. Defaults to `nil`. - `&block` (Proc) - Optional - Alternative proc form: `block.call(input, type)`. - `**` (kwargs) - Optional - Accepted and discarded. ### Returns `Dry::Struct::Constructor` wrapping `self`. ### Example ```ruby type = Test::User.constructor do |input, type| type.(input) { type.(defaults.merge(input)) } end type.(address: {city: "London", zipcode: 123_123}) #=> a Test::User (defaults filled on 2nd try) ``` ``` -------------------------------- ### Usage of #new with error handling Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/struct.md Shows how to use the `new` method to create a modified copy and demonstrates error handling when an invalid types is passed. The error message contains the original struct and the type error details. ```ruby rom_n_roda = Book.new(title: "Web", subtitle: "2nd edition") rom_n_roda.new(subtitle: "3rd edition") #=> # # error handling begin rom_n_roda.new(age: "aabb") rescue Dry::Struct::Error => e e.message #=> "[#] \"aabb\" (String) has invalid type for :age" end ``` -------------------------------- ### Super_diff failure output Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/extensions.md Example RSpec failure output when a struct equality check fails with the :super_diff extension loaded. Shows the expected and got values plus a field-level diff with - and + markers. ```text expected: # got: # (compared using eql?) # ``` -------------------------------- ### try(input) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Documentation for the `try` class method on a dry-struct class, which attempts to build a struct from input and returns a dry-types result. ```APIDOC ## try(input) ### Description Attempts to build a struct from the given input, returning a dry-types result object. On failure, it returns a failure result, optionally passing it to a block for custom error handling. ### Method try ### Endpoint Class method: `try(input)` ### Parameters - `input` (Hash{Symbol => Object}, Dry::Struct) - Required - Candidate value. - `&` (block) (Proc) - Optional - Receives the `Dry::Types::Result::Failure`; its return value replaces the failure result. ### Returns - `Dry::Types::Result::Success` with `(input)` on success. - `Dry::Types::Result::Failure` with `(input, exception)` on failure, or the block's result when given. ### Example ```ruby result = Test::User.try(name: "Jane", age: 21, address: {city: "NYC", zipcode: "1"}) result.success? #=> true Test::User.try({}) { |failure| log(failure); failure } # error-handling path ``` ``` -------------------------------- ### .constructor Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/configuration.md Wrapping/fallback coercion fn for the struct; builds `Dry::Struct::Constructor`. ```APIDOC ## .constructor ### Description Wrapping/fallback coercion fn for the struct; builds `Dry::Struct::Constructor`. ### Parameters - `constructor` / `&block` (either) - `#call` - Required: no (one required) - Coercion function to wrap or fallback. ### Default `nil` ### Source `lib/dry/struct/class_interface.rb:288-294` ``` -------------------------------- ### Handling RecycledStructError Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/compiler.md Error handling example: when the weak reference has died after garbage collection, compilation raises Dry::Struct::RecycledStructError with the message "Reference to struct class was garbage collected". ```ruby begin compiler.(collected_ast) # weakref died after GC rescue Dry::Struct::RecycledStructError => e e.message #=> "Reference to struct class was garbage collected" end ``` -------------------------------- ### Creating a constructor with callable and block forms Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/constructor.md Shows the two forms of .constructor: callable form and block form. The block form receives (input, type) and can delegate or retry on failures. ```ruby Test::User.constructor(-> x { x }) # callable form Test::User.constructor { |input, type| type.(input) } # block form (wrapping/fallback) ``` -------------------------------- ### Initialize struct with attributes hash Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/struct.md Plain assignment of the already-validated hash. Do not call directly — use `.new` (class) or `#new` (instance), or the internal class method `load`. ```ruby # @param [Hash, #each] attributes def initialize(attributes) @attributes = attributes end ``` -------------------------------- ### Load extensions with Dry::Struct.load_extensions Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/extensions.md Activates either the :pretty_print or :super_diff extension in consumer code. Requires dry-struct first, then loads the chosen extension on demand. ```ruby require "dry-struct" Dry::Struct.load_extensions(:pretty_print) # or Dry::Struct.load_extensions(:super_diff) ``` -------------------------------- ### Dry::Struct class declaration (exact) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/struct.md The exact class declaration of Dry::Struct, showing the class definition, extension of ClassInterface, deprecations, Zeitwerk loader setup, and the initial schema and abstract_class definitions. This is the base class for all structs and is declared abstract. ```ruby class Struct extend Core::Extensions include Core::Constants extend ClassInterface extend Core::Deprecations[:"dry-struct"] class << self define_method(:prepend, ::Module.method(:prepend)) def loader @loader ||= ::Zeitwerk::Loader.new.tap do |loader| root = ::File.expand_path("..", __dir__) loader.tag = "dry-struct" loader.inflector = ::Zeitwerk::GemInflector.new("#{root}/dry-struct.rb") loader.push_dir(root) loader.ignore( "#{root}/dry-struct.rb", "#{root}/dry/struct/{class_interface,errors,extensions,printer,value,version}.rb", "#{root}/dry/struct/extensions" ) end end end loader.setup include ::Dry::Equalizer(:__attributes__, inspect: false, immutable: true) defines :schema schema Types["coercible.hash"].schema(EMPTY_HASH) defines :abstract_class abstract ``` -------------------------------- ### .new(attributes = default_attributes, safe = false, &) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Creates a new struct instance from attributes, with optional safe mode and fallback block. ```APIDOC ## `.new(attributes = default_attributes, safe = false, &)` ### Description Creates a new instance of the struct class. If the input is an instance of the exact same class, it is returned as-is. If it is a subclass instance, it is coerced to the base class. Otherwise, the schema is applied to the input hash, with defaults filled in and unknown keys ignored unless the schema is strict. ### Method `.new` ### Parameters - `attributes` (Hash{Symbol => Object}, Dry::Struct) - Optional - Input hash or an existing struct instance. Defaults to `default_attributes`. - `safe` (Boolean) - Optional - When `true`, the schema runs in safe mode: on failure the block is yielded the raw input and its return value is returned instead of raising. Defaults to `false`. - `&` (block) (Proc) - Optional - Fallback for safe mode. ### Returns A new instance of the class. ### Throws `Dry::Struct::Error` wrapping any `Dry::Types::CoercionError`, with prefix `[Klass.new] ` and the original backtrace preserved. ### Example ```ruby address = Test::Address.new(city: "NYC", zipcode: "312") user = Test::User.new(name: "Jane", age: 21, address: address) user.address.equal?(address) #=> true (passed through, not rebuilt) # safe mode with fallback root_type.new(subtype_user, true) { :fallback } #=> :fallback # error handling begin Test::User.new(name: :Jane, age: "21", address: nil) rescue Dry::Struct::Error => e e.message #=> "[Test::Address.new] :city is missing in Hash input" end ``` ``` -------------------------------- ### transform_types usage with Book struct and meta inspection Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Shows how to use `transform_types` to add metadata to all attribute types. The example defines a Book struct with a type transformation that adds `struct: :Book` meta, then inspects the resulting schema key meta. ```ruby class Book < Dry::Struct transform_types { |t| t.meta(struct: :Book) } attribute :title, Types::String end Book.schema.key(:title).meta #=> {struct: :Book} ``` -------------------------------- ### Basic Dry.Struct usage with attributes Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/dry-struct.md Builds a Person struct with name and age attributes, then instantiates it. Requires dry-struct and dry-types. Shows attribute access returning the assigned values. ```ruby require "dry-struct" module Types include Dry.Types() # from dry-types: provides Types::String, Types::Integer, ... end Person = Dry.Struct(name: Types::String, age: Types::Integer) matz = Person.new(name: "Matz", age: 52) matz.name #=> "Matz" matz.age #=> 52 ``` -------------------------------- ### Dry::Struct::ClassInterface#meta - Get or set metadata Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Defines the .meta method on struct classes. When called with no arguments, returns the current schema metadata. When called with an empty hash, returns self. When called with a non-empty hash, returns a new anonymous subclass with the metadata merged into its schema. ```ruby def meta(meta = Undefined) if meta.equal?(Undefined) schema.meta elsif meta.empty? self else ::Class.new(self) do schema schema.meta(meta) unless meta.empty? end end end ``` -------------------------------- ### #inspect Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/struct.md Returns a human-readable string representation of the struct instance, showing the class name and attribute values in the order defined by attribute_names. ```APIDOC ## #inspect ### Description Returns a human-readable string representation of the struct instance, showing the class name and attribute values in the order defined by attribute_names. ### Method `inspect` ### Returns `String` in the form `#`. Uses `attribute_names` for ordering; unnamed (anonymous) classes fall back to `klass.inspect`. ### Source `lib/dry/struct.rb:215-218` ``` -------------------------------- ### attributes_from usage with Address and Buyer structs Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Demonstrates using `attributes_from` to inline attributes from an Address struct into a Buyer struct. Shows that Buyer can then be instantiated with the inlined attributes. ```ruby class Address < Dry::Struct attribute :city, Types::String attribute :zipcode, Types::String end class Buyer < Dry::Struct attribute :name, Types::String attributes_from Address # inlines :city, :zipcode end Buyer.new(name: "Jane", city: "NYC", zipcode: "10001") ``` -------------------------------- ### StructBuilder#call implementation Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/struct-builder.md Creates a nested struct class, registers it as a constant on the parent, and returns the attribute type. When no superclass is given, the new class's schema starts from a cleared copy of the abstract class's schema. Throws Dry::Struct::Error if the constant already exists directly under the parent. ```ruby # @param [Symbol|String] attr_name the name of the nested type # @param [Dry::Struct,Dry::Types::Type::Array,Undefined] type the superclass # of the nested struct # @yield the body of the nested struct def call(attr_name, type, &block) const_name = const_name(type, attr_name) check_name(const_name) builder = self parent = parent(type) new_type = ::Class.new(Undefined.default(parent, struct.abstract_class)) do if Undefined.equal?(parent) schema builder.struct.schema.clear end class_exec(&block) end struct.const_set(const_name, new_type) if array?(type) type.of(new_type) elsif optional?(type) new_type.optional else new_type end end ``` -------------------------------- ### Dry::Struct .new usage examples Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Shows typical .new behavior: nested struct instances pass through unchanged, safe mode returns the block's fallback value on failure, and coercion errors raise Dry::Struct::Error with a descriptive message. Demonstrates pass-through, safe fallback, and error handling. ```ruby address = Test::Address.new(city: "NYC", zipcode: "312") user = Test::User.new(name: "Jane", age: 21, address: address) user.address.equal?(address) #=> true (passed through, not rebuilt) # safe mode with fallback root_type.new(subtype_user, true) { :fallback } #=> :fallback # error handling begin Test::User.new(name: :Jane, age: "21", address: nil) rescue Dry::Struct::Error => e e.message #=> "[Test::Address.new] :city is missing in Hash input" end ``` -------------------------------- ### Sum#try implementation Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/sum.md The try method returns a Success result immediately for struct instances, otherwise delegates to the constrained-sum try. ```ruby def try(input) if input.is_a?(Struct) ::Dry::Types::Result::Success.new(try_struct(input) { return super }) else super end end ``` -------------------------------- ### .new(...) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/configuration.md Safe construction: on failure the block is yielded the raw input and its result returned instead of raising. ```APIDOC ## .new(...) ### Description Safe construction: on failure the block is yielded the raw input and its result returned instead of raising. ### Parameters - `safe` (Boolean) - Required: no - Default: `false` - If true, on failure the block is yielded the raw input and its result returned instead of raising. ### Source `lib/dry/struct/class_interface.rb:239-259` ``` -------------------------------- ### #try(input) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/sum.md The `try` method on `Dry::Struct::Sum` returns a `Dry::Types::Result::Success` immediately when the input is a struct instance matched directly. Otherwise, it delegates to the constrained-sum `try`, which yields a `Dry::Types::Result::Failure` to a block if given. ```APIDOC ## `#try(input)` ### Description Returns a `Dry::Types::Result::Success` immediately when the input is a struct instance matched directly. Otherwise, it delegates to the constrained-sum `try`, which yields a `Dry::Types::Result::Failure` to a block if given. ### Method `try` ### Parameters - `input` (Hash{Symbol => Object}, Dry::Struct) - Required - Candidate value. ### Returns - `Dry::Types::Result::Success` — immediately when `input` is a struct instance matched directly. - Otherwise, delegates to the constrained-sum `try` (which yields a `Dry::Types::Result::Failure` to a block if given). ### Example ```ruby sum.try(Test::City.new(name: "London")).success? #=> true sum.try(name: 123).success? #=> false ``` ``` -------------------------------- ### Dry::Struct.load_extensions(:pretty_print) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/extensions.md Loads the pretty_print extension, which adds a #pretty_print method to Dry::Struct instances for readable output. ```APIDOC ## Dry::Struct.load_extensions(:pretty_print) ### Description Loads the `:pretty_print` extension, which adds a `#pretty_print` method to `Dry::Struct` instances. This method renders the struct as a grouped `#` block with each attribute on its own line, using Ruby's `pp` library. ### Method `load_extensions` (class method on `Dry::Struct`) ### Parameters - `extension` (Symbol) - Required - The extension name to load, e.g., `:pretty_print`. ### Usage Example ```ruby require "dry-struct" Dry::Struct.load_extensions(:pretty_print) pp user #=> #> ``` ### Notes - The extension is loaded on demand; it is not required eagerly. - After loading, the `#pretty_print` method becomes part of `Dry::Struct`'s public surface. ``` -------------------------------- ### .call(input) / .[] Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/class-interface.md Coerces input into a struct instance using unsafe mode, equivalent to `.new` without safe mode. ```APIDOC ## `.call(input)` and `.[]` alias ### Description `call` is provided by the `Types::Type` interface (dry-types) and is the same entry point as `.[]`. Both perform unsafe coercion with the same rules as `.new`. ### Method `.call` / `.[]` ### Parameters - `input` (Object) - Required - The input to coerce into a struct instance. ### Returns A new struct instance. ### Example ```ruby Test::User[attributes] # same as Test::User.call(attributes) ``` ``` -------------------------------- ### #pretty_print(pp) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/extensions.md Instance method added by the :pretty_print extension. Renders the struct as a grouped # block with each attribute on its own line. ```APIDOC ## #pretty_print(pp) ### Description Renders the struct as a grouped `#` block with each attribute on its own line, wrapped inside `pp`'s grouping. Nested structs recurse because their own attributes are pretty-printed via `pp.pp column_value`. ### Method `pretty_print` (instance method on `Dry::Struct`) ### Parameters - `pp` (PP) - Required - The pretty-print context instance, normally supplied by `pp obj` / `pp(pp)` machinery. ### Returns `nil` (renders into `pp`). ### Example Output ```ruby #> ``` ``` -------------------------------- ### Register extensions in lib/dry/struct/extensions.rb Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/extensions.md Registers the :pretty_print and :super_diff extensions with dry-core's extension registry. Both are loaded only on demand via Dry::Struct.load_extensions. ```ruby Dry::Struct.register_extension(:pretty_print) do require "dry/struct/extensions/pretty_print" end Dry::Struct.register_extension(:super_diff) do require "dry/struct/extensions/super_diff" end ``` -------------------------------- ### Rescue MissingAttributeError Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/errors.md Shows how to rescue MissingAttributeError when accessing an undefined attribute. It can also be rescued as KeyError. ```ruby begin struct[:missing] rescue Dry::Struct::MissingAttributeError => e e.message #=> "Missing attribute: :missing on Test::Task" # also rescue-able as ::KeyError end ``` -------------------------------- ### Dry::Struct::Compiler.new(registry) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/compiler.md Instantiates a compiler with a types registry used to resolve string/Dry::Types references in the schema AST. Inherited from Types::Compiler. ```APIDOC ## Dry::Struct::Compiler.new(registry) ### Description Creates a new compiler instance. The registry is used to resolve string/`Dry::Types[...]` references embedded in the schema AST. ### Method Constructor ### Parameters - **registry** (Dry::Types registry) - Required - The types registry to use for resolving references. ### Example ```ruby compiler = Dry::Struct::Compiler.new(Dry::Types) ``` ``` -------------------------------- ### Convert struct instances to hashes Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/struct.md Shows the output of `#to_h` for a struct with a present attribute and for a struct with nested structs, which are converted recursively. ```ruby rom_n_roda.to_h #=> {title: "Refactoring"} # nested structs are converted too user.to_h #=> {name: "Jane", age: 21, address: {city: "NYC", zipcode: "123"}} ``` -------------------------------- ### #new(changeset) / #__new__ (alias) Source: https://github.com/dry-rb/dry-struct/blob/main/_autodocs/api-reference/struct.md Creates a new instance of the same struct class with partial attribute overrides applied on top of the existing attributes. It performs a shallow merge, preserves already-coerced values, and does not re-apply defaults. ```APIDOC ## #new(changeset) / #__new__ (alias) ### Description Creates a new instance of the same struct class with partial attribute overrides applied on top of the existing attributes. It performs a shallow merge, preserves already-coerced values, and does not re-apply defaults. ### Method `new` (alias: `__new__`) ### Parameters - `changeset` (Hash{Symbol => Object}) - Required - Partial attribute overrides. ### Returns A new instance of the same class with the overrides applied on top of `__attributes__`. ### Throws `Dry::Struct::Error` wrapping `Dry::Types::SchemaError`, `Dry::Types::MissingKeyError` or `Dry::Types::UnknownKeysError`. ### Behavioral Details - Attributes not present in the changeset keep their existing **already-coerced** values; defaults are **not** re-applied (`resolve_defaults: false`). - It is a shallow merge — a nested hash in the changeset replaces the whole nested struct (there is no deep merge). - Values that are already struct instances pass through unchanged. - `__new__` exists so user code that defines its own `new` can still create copies. ### Example ```ruby rom_n_roda = Book.new(title: "Web", subtitle: "2nd edition") rom_n_roda.new(subtitle: "3rd edition") #=> # # error handling begin rom_n_roda.new(age: "aabb") rescue Dry::Struct::Error => e e.message #=> "[#] \"aabb\" (String) has invalid type for :age" end ``` ### Source `lib/dry/struct.rb:202-212` ```