---
- version: 1.7.1
  date: 2025-01-31
  fixed:
  - "Syntax errors on 3.3.0 (@flash-gordon, see https://github.com/dry-rb/dry-types/issues/478)"
- version: 1.7.0
  summary:
  date: 2025-01-06
  fixed:
  - 'Fixed coercion errors for structs (issue #192 via #193)
    (@flash-gordon)'
  - "Invalid method names are now allowed as struct attributes (issue #169 via #195) (@flash-gordon)"
  changed:
  - 'Missing attribute error now includes the name of the class (issue #170 via #191)
    (@phillipoertel + @cllns)'
  - '3.1 is now the minimum Ruby version (@flash-gordon)'
  - '`Dry::Struct::Error` is now a subclass of `Dry::Types::CoercionError` (in #193)
    (@flash-gordon)'
  - '`Dry::Struct#[]` now returns `nil` if an optional attribute is not set.
    This is consistent with calling accessor methods for optional attributes.
    (issue #171 via #194) (@ivleonov + @flash-gordon)'
- version: 1.6.0
  date: 2022-11-04
  changed:
  - This version uses dry-core 1.0 (@flash-gordon + @solnic)
- version: 1.5.2
  date: '2022-10-19'
  fixed:
  - Coercion failures keep the original error instead of just having a string (@flash-gordon
    + @newx)
- version: 1.5.1
  date: '2022-10-17'
  fixed:
  - 'Fixed issues with auto-loading `Extensions` module (issue #183 fixed via #184)
    (@solnic)'
- version: 1.5.0
  date: '2022-10-15'
  added:
  changed:
  - Use zeitwerk for auto-loading (@flash-gordon)
- version: 1.4.0
  date: '2021-01-21'
  added:
  - Support for wrapping constructors and fallbacks, see release notes for dry-types
    1.5.0 (@flash-gordon)
  - |-
    Improvements of the attribute DSL, now it's possible to use optional structs as a base class (@flash-gordon)
      ```ruby
      class User < Dry::Struct
        attribute :name, Types::String
        attribute :address, Dry::Struct.optional do
          attribute :city, Types::String
        end
      end

      User.new(name: "John", address: nil) # => #<User name="John" address=nil>
      ```
- version: 1.3.0
  date: '2020-02-10'
  added:
  - |-
    Nested structures will reuse type and key transformations from the enclosing struct (@flash-gordon)

      ```ruby
      class User < Dry::Struct
        transform_keys(&:to_sym)

        attribute :name, Types::String
        attribute :address do
          # this struct will inherit transform_keys(&:to_sym)
          attribute :city, Types::String
        end

        # nested struct will _not_ transform keys because a parent
        # struct is given
        attribute :contacts, Dry::Struct do
          attribute :email, Types::String
        end
      end
      ```
  - "`Dry::Struct::Constructor` finally acts like a fully-featured type (@flash-gordon)"
  - "`Dry::Struct.abstract` declares a struct class as abstract. An abstract class
    is used as a default superclass for nested structs (@flash-gordon)"
  - "`Dry::Struct.to_ast` and struct compiler (@flash-gordon)"
  - |-
    Struct composition with `Dry::Struct.attributes_from`. It's more flexible than inheritance (@waiting-for-dev + @flash-gordon)

      ```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
      end

      class Seller < Dry::Struct
        attribute :name, Types::String
        attribute :email, Types::String
        attributes_from Address
      end
      ```
  changed:
  - "[internal] metadata is now stored inside schema (@flash-gordon)"
- version: 1.2.0
  date: '2019-12-20'
  changed:
  - "`Dry::Struct::Value` is deprecated. `Dry::Struct` instances were never meant
    to be mutable, we have no support for this. The only difference between `Dry::Struct`
    and `Dry::Struct::Value` is that the latter is deeply frozen. Freezing objects
    slows the code down and gives you very little benefit in return. If you have a
    use case for `Value`, it won't be hard to roll your own solution using [ice_nine](https://github.com/dkubb/ice_nine)
    (flash-gordon)"
  - In the thread of the previous change, structs now use immutable equalizer. This
    means `Struct#hash` memoizes its value after the first invocation. Depending on
    the case, this may speed up your code significantly (flash-gordon)
- version: 1.1.1
  date: '2019-10-13'
  changed:
  - |-
    Pattern matching syntax is simplified with `deconstruct_keys` (k-tsj)

      ```ruby
      User = Dry.Struct(name: 'string', email: 'string')

      user = User.new(name: 'John Doe', email: 'john@acme.org')

      case user
      in User(name: 'John Doe', email:)
        puts email
      else
        puts 'Not John'
      end
      ```

      See more examples in the [specs](https://github.com/dry-rb/dry-struct/blob/8112772eb08d22ff2cd3e6997514d79a9b124968/spec/dry/struct/pattern_matching_spec.rb).
- version: 1.1.0
  date: '2019-10-07'
  added:
  - 'Experimental support for pattern matching :tada: (flash-gordon)'
- version: 1.0.0
  date: '2019-04-23'
  changed:
  - "`valid?` and `===` behave differently, `===` works the same way `Class#===` does
    and `valid?` checks if the value _can be_ coerced to the struct (flash-gordon)"
  added:
  - |-
    `Struct.call` now accepts an optional block that will be called on failed coercion. This behavior is consistent with dry-types 1.0. Note that `.new` doesn't take a block (flash-gordon)
      ```ruby
      User = Dry::Struct(name: 'string')
      User.(1) { :oh_no }
      # => :oh_no
      ```
- version: 0.7.0
  date: '2019-03-22'
  changed:
  - |-
    [BREAKING] `Struct.input` was renamed `Struct.schema`, hence `Struct.schema` returns an instance of `Dry::Types::Hash::Schema` rather than a `Hash`. Schemas are also implementing `Enumerable` but they iterate over key types.
      New API:
      ```ruby
      User.schema.each do |key|
        puts "Key name: #{ key.name }"
        puts "Key type: #{ key.type }"
      end
      ```
      To get a type by its name use `.key`:
      ```ruby
      User.schema.key(:id) # => #<Dry::Types::Hash::Key ...>
      ```
  - |-
    [BREAKING] `transform_types` now passes one argument to the block, an instance of the `Key` type. Combined with the new API from dry-types it simplifies declaring omittable keys:
      ```ruby
      class StructWithOptionalKeys < Dry::Struct
        transform_types { |key| key.required(false) }
        # or simply
        transform_types(&:omittable)
      end
      ```
  - "`Dry::Stuct#new` is now more efficient for partial updates (flash-gordon)"
  - Ruby 2.3 is EOL and not officially supported. It may work but we don't test it.
- version: 0.6.0
  date: '2018-10-24'
  changed:
  - "[BREAKING] `Struct.attribute?` in the old sense is deprecated, use `has_attribute?`
    as a replacement"
  added:
  - |-
    `Struct.attribute?` is an easy way to define omittable attributes (flash-gordon):

      ```ruby
      class User < Dry::Struct
        attribute  :name,  Types::Strict::String
        attribute? :email, Types::Strict::String
      end
      # User.new(name: 'John') # => #<User name="John">
      ```
  fixed:
  - "`Struct#to_h` recursively converts hash values to hashes, this was done to be
    consistent with current behavior for arrays (oeoeaio + ZimbiX)"
- version: 0.5.1
  date: '2018-08-11'
  fixed:
  - Constant resolution is now restricted to the current module when structs are automatically
    defined using the block syntax. This shouldn't break any existing code (piktur)
  added:
  - |-
    Pretty print extension (ojab)
      ```ruby
      Dry::Struct.load_extensions(:pretty_print)
      PP.pp(user)
      #<Test::User
       name="Jane",
       age=21,
       address=#<Test::Address city="NYC", zipcode="123">>
      ```
- version: 0.5.0
  date: '2018-05-03'
  added:
  - |-
    `Dry::Struct.transform_types` accepts a block which is yielded on every type to add. Since types are `dry-types`' objects that come with a robust DSL it's rather simple to restore the behavior of `constructor_type`. See https://github.com/dry-rb/dry-struct/pull/64 for details (flash-gordon)

      Example: evaluate defaults on `nil` values

      ```ruby
      class User < Dry::Struct
        transform_types do |type|
          type.constructor { |value| value.nil? ? Undefined : value  }
        end
      end
      ```
  - "`Data::Struct.transform_keys` accepts a block/proc that transforms keys of input
    hashes. The most obvious usage is simbolization but arbitrary transformations
    are allowed (flash-gordon)"
  - |-
    `Dry.Struct` builds a struct by a hash of attribute names and types (citizen428)

      ```ruby
      User = Dry::Struct(name: 'strict.string') do
        attribute :email, 'strict.string'
      end
      ```
  - |-
    Support for `Struct.meta`, note that `.meta` returns a _new class_ (flash-gordon)

      ```ruby
      class User < Dry::Struct
        attribute :name, Dry::Types['strict.string']
      end

      UserWithMeta = User.meta(foo: :bar)

      User.new(name: 'Jade').class == UserWithMeta.new(name: 'Jade').class # => false
      ```
  - |-
    `Struct.attribute` yields a block with definition for nested structs. It defines a nested constant for the new struct and supports arrays (AMHOL + flash-gordon)

      ```ruby
        class User < Dry::Struct
          attribute :name, Types::Strict::String
          attribute :address do
            attribute :country, Types::Strict::String
            attribute :city, Types::Strict::String
          end
          attribute :accounts, Types::Strict::Array do
            attribute :currency, Types::Strict::String
            attribute :balance, Types::Strict::Decimal
          end
        end

        # ^This automatically defines User::Address and User::Account
      ```
  fixed:
  - Adding a new attribute invalidates `attribute_names` (flash-gordon)
  - Struct classes track subclasses and define attributes in them, now it doesn't
    matter whether you define attributes first and _then_ subclass or vice versa.
    Note this can lead to memory leaks in Rails environment when struct classes are
    reloaded (flash-gordon)
- version: 0.4.0
  date: '2017-11-04'
  changed:
  - Attribute readers don't override existing instance methods (solnic)
  - "`Struct#new` uses raw attributes instead of method calls, this makes the behavior
    consistent with the change above (flash-gordon)"
  - "`constructor_type` now actively rejects `:weak` and `:symbolized` values (GustavoCaso)"
  fixed:
  - "`Struct#new` doesn't call `.to_hash` recursively (flash-gordon)"
- version: 0.3.1
  date: '2017-06-30'
  added:
  - "`Struct.constructor` that makes dry-struct more aligned with dry-types; now you
    can have a struct with a custom constructor that will be called _before_ calling
    the `new` method (v-kolesnikov)"
  - "`Struct.attribute?` and `Struct.attribute_names` for introspecting struct attributes
    (flash-gordon)"
  - "`Struct#__new__` is a safe-to-use-in-gems alias for `Struct#new` (flash-gordon)"
- version: 0.3.0
  date: '2017-05-05'
  added:
  - "`Dry::Struct#new` method to return new instance with applied changeset (Kukunin)"
  fixed:
  - "`.[]` and `.call` does not coerce subclass to superclass anymore (Kukunin)"
  - Raise ArgumentError when attribute type is a string and no value provided is for
    `new` (GustavoCaso)
  changed:
  - "`.new` without arguments doesn't use nil as an input for non-default types anymore
    (flash-gordon)"
- version: 0.2.1
  date: '2017-02-27'
  fixed:
  - Fixed `Dry::Struct::Value` which appeared to be broken in the last release (flash-gordon)
- version: 0.2.0
  date: '2016-02-26'
  changed:
  - Struct attributes can be overridden in a subclass (flash-gordon)
- version: 0.1.1
  date: '2016-11-13'
  fixed:
  - Make `Dry::Struct` act as a constrained type. This fixes the behavior of sum types
    containing structs (flash-gordon)
- version: 0.1.0
  date: '2016-09-21'
  added:
  - "`:strict_with_defaults` constructor type (backus)"
  changed:
  - "[BREAKING] `:strict` was renamed to `:permissive` as it ignores missing keys
    (backus)"
  - "[BREAKING] `:strict` now raises on unexpected keys (backus)"
  - Structs no longer auto-register themselves in the types container as they implement
    `Type` interface and we don't have to wrap them in `Type::Definition` (flash-gordon)
- version: 0.0.1
  date: '2016-07-17'
  summary: Initial release of code imported from dry-types
