Skip to content

Releases: dry-rb/dry-types

v0.15.0

22 Mar 13:37
v0.15.0
c85f756
Compare
Choose a tag to compare

0.15.0 2019-03-22

Changed

  • [BREAKING] Internal representation of hash schemas was changed to be a simple list of key types (flash-gordon)
    Dry::Types::Hash#with_type_transform now yields a key type instead of type + name:
    Dry::Types['strict.hash'].with_type_transform { |key| key.name == :age ? key.required(false) : key }
  • [BREAKING] Definition types were renamed to nominal (flash-gordon)
  • [BREAKING] Top-level types returned by Dry::Types.[] are now strict (flash-gordon)
    # before
    Dry::Types['integer']
    # => #<Dry::Types[Nominal<Integer>]>
    # now
    Dry::Types['integer']
    # => <Dry::Types[Constrained<Nominal<Integer> rule=[type?(Integer)]>]>
    # you can still access nominal types using namespace
    Dry::Types['nominal.integer']
    # => #<Dry::Types[Nominal<Integer>]>
  • [BREAKING] Default values are not evaluated if the decorated type returns nil. They are triggered on Undefined instead (GustavoCaso + flash-gordon)
  • [BREAKING] Support for old hash schemas was fully removed. This makes dry-types not compatible with dry-validation < 1.0 (flash-gordon)
  • Dry::Types.module is deprecated in favor of Dry.Types (flash-gordon)
    Keep in mind Dry.Types uses strict types for top-level names, that is after
    module Types
      include Dry.Types
    end
    Types::Integer is a strict type. If you want it to be nominal, use include Dry.Types(default: :nominal). See other options below.
  • params.integer now always converts strings to decimal numbers, this means 09 will be coerced to 9 (threw an error before) (skryukov)
  • Ruby 2.3 is EOL and not officially supported. It may work but we don't test it.

Added

  • Improved string representation of types (flash-gordon)
    Dry::Types['nominal.integer']
    # => #<Dry::Types[Nominal<Integer>]>
    Dry::Types['params.integer']
    # => #<Dry::Types[Constructor<Nominal<Integer> fn=Dry::Types::Coercions::Params.to_int>]>
    Dry::Types['hash'].schema(age?: 'integer')
    # => #<Dry::Types[Constrained<Schema<keys={age?: Constrained<Nominal<Integer> rule=[type?(Integer)]>}> rule=[type?(Hash)]>]>
    Dry::Types['array<integer>']
    # => #<Dry::Types[Constrained<Array<Constrained<Nominal<Integer> rule=[type?(Integer)]>> rule=[type?(Array)]>]>
  • Options for the list of types you want to import with Dry.Types (flash-gordon)
    Cherry-pick only certain types:
    module Types
      include Dry.Types(:strict, :nominal, :coercible)
    end
    Types.constants
    # => [:Strict, :Nominal, :Coercible]
    Change default top-level types:
    module Types
      include Dry.Types(default: :coercible)
    end
    # => #<Dry::Types[Constructor<Nominal<Integer> fn=Kernel.Integer>]>
    Rename type namespaces:
    module Types
      include Dry.Types(strict: :Strong, coercible: :Kernel)
    end
  • Optional keys for schemas can be provided with ?-ending symbols (flash-gordon)
    Dry::Types['hash'].schema(name: 'string', age?: 'integer')
  • Another way of making keys optional is setting required: false to meta. In fact, it is the preferable
    way if you have to store this information in meta, otherwise use the Key's API (see below) (flash-gordon)
    Dry::Types['hash'].schema(
      name: Dry::Types['string'],
      age: Dry::Types['integer'].meta(required: false)
    )
  • Key types have API for making keys omittable and back (flash-gordon)
    # defining a base schema with optional keys
    lax_hash = Dry::Types['hash'].with_type_transform { |key| key.required(false) }
    # same as
    lax_hash = Dry::Types['hash'].with_type_transform(&:omittable)
    
    # keys in user_schema are not required
    user_schema = lax_hash.schema(name: 'string', age: 'integer')
  • Type#optional? now recognizes more cases where nil is an allowed value (flash-gordon)
  • Constructor#{prepend,append} with << and >> as aliases. Constructor#append works the same way Constructor#constrcutor does. Constuctor#prepend chains functions in the reverse order, see examples (flash-gordon)
    to_int = Types::Coercible::Integer
    inc = to_int.append { |x| x + 2 }
    inc.("1") # => "1" -> 1 -> 3
    
    inc = to_int.prepend { |x| x + "2" }
    inc.("1") # => "1" -> "12" -> 12
  • Partial schema application for cases when you want to validate only a subset of keys (flash-gordon)
    This is useful when you want to update a key or two in an already-validated hash. A perfect example is Dry::Struct#new where this feature is now used.
    schema = Dry::Types['hash'].schema(name: 'string', age: 'integer')
    value = schema.(name: 'John', age: 20)
    update = schema.apply({ age: 21 }, skip_missing: true)
    value.merge(update)

Fixed

  • Hash::Map now behaves as a constrained type if its values are constrained (flash-gordon)
  • coercible.integer now doesn't blow up on invalid strings (exterm)

Compare v0.14.0...v0.15.0

v0.14.0

22 Mar 13:22
v0.14.0
7c7a682
Compare
Choose a tag to compare

0.14.0 2019-01-29

Changed

  • [BREAKING] Support for Ruby 2.2 was dropped. It reached EOL on March 31, 2018.
  • dry-logic was updated to ~> 0.5 (solnic)

Fixed

  • valid? works correctly with constructors now (cgeorgii)

Compare v0.13.4...v0.14.0

v0.13.4

21 Dec 13:05
v0.13.4
2cecc4f
Compare
Choose a tag to compare

v0.13.4 2018-12-21

Fixed

v0.13.3

25 Nov 15:20
v0.13.3
287e732
Compare
Choose a tag to compare

v0.13.3 2018-11-25

Fixed

  • Dry::Types::Hash#try returns Failure instead of throwing an exception on missing keys (GustavoCaso)

Compare v0.13.2...v0.13.3

v0.12.3

12 Jun 13:42
v0.12.3
4ea47e0
Compare
Choose a tag to compare

v0.12.3 2018-06-12

Fixed

  • Fixed constrained? for constructor types (solnic)

Compare v0.12.2...v0.12.3

v0.13.2

30 May 12:06
v0.13.2
b847b21
Compare
Choose a tag to compare

v0.13.2 2018-05-30

Fixed

  • Defaults#valid? now works fine when passing Dry::Core::Constans::Undefined as value (GustavoCaso)
  • valid? for constructor types wrapping Sums (GustavoCaso)

Compare v0.13.1...v0.13.2

v0.13.1

28 May 09:39
v0.13.1
45c818d
Compare
Choose a tag to compare

v0.13.1 2018-05-28

Fixed

  • Defaults now works fine with meta (GustavoCaso)
  • Defaults are now re-decorated properly (flash-gordon)

Added

  • params.int was added to make the upgrade process in dry-validation smoother (available after you require 'dry/types/compat/int') (flash-gordon)

Compare v0.13.0...v0.13.1

v0.13.0

03 May 15:19
v0.13.0
caf0c99
Compare
Choose a tag to compare

v0.13.0 2018-05-03

Changed

  • [BREAKING] Renamed Types::Form to Types::Params. You can opt-in the former name with require 'dry/types/compat/form_types'. It will be dropped in the next release (ndrluis)
  • [BREAKING] The Int types was renamed to Integer, this was the only type named differently from the standard Ruby classes so it has been made consistent. The former name is available with require 'dry/types/compat/int' (GustavoCaso + flash-gordon)
  • [BREAKING] Default types are not evaluated on nil. Default values are evaluated only if no value were given.
      type = Types::Strict::String.default("hello")
      type[nil] # => constraint error
      type[] # => "hello"
    This change allowed to greatly simplify hash schemas, make them a lot more flexible yet predictable (see below).
  • [BREAKING] Dry::Types.register_class was removed, Dry::Types.register was made private API, do not register your types in the global dry-types container, use a module instead, e.g. Types (flash-gordon)
  • [BREAKING] Enum types don't accept value index anymore. Instead, explicit mapping is supported, see below (flash-gordon)

Added

  • Hash schemas were rewritten. The old API is still around but is going to be deprecated and removed before 1.0. The new API is simpler and more flexible. Instead of having a bunch of predefined schemas you can build your own by combining the following methods:

    1. Schema#with_key_transform—transforms keys of input hashes, for things like symbolizing etc.
    2. Schema#strict—makes a schema intolerant to unknown keys.
    3. Hash#with_type_transform—transforms member types with an arbitrary block. For instance,
    optional_keys = Types::Hash.with_type_transform { |t, _key| t.optional }
    schema = optional_keys.schema(name: 'strict.string', age: 'strict.int')
    schema.(name: "Jane", age: nil) # => {name: "Jane", age: nil}

    Note that by default all keys are required, if a key is expected to absent, add to the corresponding type's meta omittable: true:

    intolerant = Types::Hash.schema(name: Types::Strict::String)
    intolerant[{}] # => Dry::Types::MissingKeyError
    tolerant = Types::Hash.schema(name: Types::Strict::String.meta(omittable: true))
    tolerant[{}] # => {}
    tolerant_with_default = Types::Hash.schema(name: Types::Strict::String.meta(omittable: true).default("John"))
    tolerant[{}] # => {name: "John"}

    The new API is composable in a natural way:

    TOLERANT = Types::Hash.with_type_transform { |t| t.meta(omittable: true) }.freeze
    user = TOLERANT.schema(name: 'strict.string', age: 'strict.int')
    user.(name: "Jane") # => {name: "Jane"}
    
    TOLERANT_SYMBOLIZED = TOLERANT.with_key_transform(&:to_sym)
    user_sym = TOLERANT_SYMBOLIZED.schema(name: 'strict.string', age: 'strict.int')
    user_sym.("name" => "Jane") # => {name: "Jane"}

    (flash-gordon)

  • Types.Strict is an alias for Types.Instance (flash-gordon)

    strict_range = Types.Strict(Range)
    strict_range == Types.Instance(Range) # => true
  • Enum#include? is an alias to Enum#valud? (d-Pixie + flash-gordon)

  • Range was added (GustavoCaso)

  • Array types filter out Undefined values, if you have an array type with a constructor type as its member, the constructor now can return Dry::Types::Undefined to indicate empty value:

    filter_empty_strings = Types::Strict::Array.of(
      Types::Strict::String.constructor { |input|
        input.to_s.yield_self { |s| s.empty? ? Dry::Types::Undefined : s }
      }
    )
    filter_empty_strings.(["John", nil, "", "Jane"]) # => ["John", "Jane"]
  • Types::Map was added for homogeneous hashes, when only types of keys and values are known in advance, not specific key names (fledman + flash-gordon)

      int_to_string = Types::Hash.map('strict.integer', 'strict.string')
      int_to_string[0 => 'foo'] # => { 0 => "foo" }
      int_to_string[0 => 1] # Dry::Types::MapError: input value 1 for key 0 is invalid: type?(String, 1)
  • Enum supports mappings (bolshakov + flash-gordon)

    dict = Types::Strict::String.enum('draft' => 0, 'published' => 10, 'archived' => 20)
    dict['published'] # => 'published'
    dict[10] # => 'published'

Fixed

  • Fixed applying constraints to optional type, i.e. .optional.constrained works correctly (flash-gordon)
  • Fixed enum working with optionals (flash-gordon)

Internal

  • Dropped the dry-configurable dependency (GustavoCaso)
  • The gem now uses dry-inflector for inflections instead of inflecto (GustavoCaso)

Compare v0.12.2...v0.13.0

v0.12.2

04 Nov 14:33
v0.12.2
1697dd1
Compare
Choose a tag to compare

v0.12.2 2017-11-04

Fixed

  • The type compiler was fixed for simple rules such as used for strict type checks (flash-gordon)
  • Fixed an error on Dry::Types['json.decimal'].try(nil) (nesaulov)
  • Fixed an error on calling try on an array type built of constrained types (flash-gordon)
  • Implemented === for enum types (GustavoCaso)

Compare v0.12.1...v0.12.2

v0.12.1

04 Nov 14:33
Compare
Choose a tag to compare

v0.12.1 2017-10-11

Fixed

  • Constructor#try rescues ArgumentError (raised in cases like Integer('foo')) (flash-gordon)
  • #constructor works correctly for default and enum types (solnic)
  • Optional sum types work correctly in safe mode (GustavoCaso)
  • The equalizer of constrained types respects meta (flash-gordon)

Compare v0.12.0...v0.12.1