Releases: dry-rb/dry-types
v0.15.0
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 onUndefined
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 ofDry.Types
(flash-gordon)
Keep in mindDry.Types
uses strict types for top-level names, that is aftermodule Types include Dry.Types end
Types::Integer
is a strict type. If you want it to be nominal, useinclude Dry.Types(default: :nominal)
. See other options below.params.integer
now always converts strings to decimal numbers, this means09
will be coerced to9
(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:Change default top-level types:module Types include Dry.Types(:strict, :nominal, :coercible) end Types.constants # => [:Strict, :Nominal, :Coercible]
Rename type namespaces:module Types include Dry.Types(default: :coercible) end # => #<Dry::Types[Constructor<Nominal<Integer> fn=Kernel.Integer>]>
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 inmeta
, 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 wherenil
is an allowed value (flash-gordon)Constructor#{prepend,append}
with<<
and>>
as aliases.Constructor#append
works the same wayConstructor#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 isDry::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)
v0.14.0
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)
v0.13.4
v0.13.4 2018-12-21
Fixed
- Fixed warnings about keyword arguments from Ruby 2.6. See https://bugs.ruby-lang.org/issues/14183 for all the details (flash-gordon)
v0.13.3
v0.13.3 2018-11-25
Fixed
Dry::Types::Hash#try
returnsFailure
instead of throwing an exception on missing keys (GustavoCaso)
v0.12.3
v0.12.3 2018-06-12
Fixed
- Fixed
constrained?
for constructor types (solnic)
v0.13.2
v0.13.2 2018-05-30
Fixed
Defaults#valid?
now works fine when passingDry::Core::Constans::Undefined
as value (GustavoCaso)valid?
for constructor types wrappingSum
s (GustavoCaso)
v0.13.1
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 yourequire 'dry/types/compat/int'
) (flash-gordon)
v0.13.0
v0.13.0 2018-05-03
Changed
- [BREAKING] Renamed
Types::Form
toTypes::Params
. You can opt-in the former name withrequire 'dry/types/compat/form_types'
. It will be dropped in the next release (ndrluis) - [BREAKING] The
Int
types was renamed toInteger
, this was the only type named differently from the standard Ruby classes so it has been made consistent. The former name is available withrequire '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.This change allowed to greatly simplify hash schemas, make them a lot more flexible yet predictable (see below).type = Types::Strict::String.default("hello") type[nil] # => constraint error type[] # => "hello"
- [BREAKING]
Dry::Types.register_class
was removed,Dry::Types.register
was made private API, do not register your types in the globaldry-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:
Schema#with_key_transform
—transforms keys of input hashes, for things like symbolizing etc.Schema#strict
—makes a schema intolerant to unknown keys.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 forTypes.Instance
(flash-gordon)strict_range = Types.Strict(Range) strict_range == Types.Instance(Range) # => true
-
Enum#include?
is an alias toEnum#valud?
(d-Pixie + flash-gordon) -
Range
was added (GustavoCaso) -
Array
types filter outUndefined
values, if you have an array type with a constructor type as its member, the constructor now can returnDry::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 ofinflecto
(GustavoCaso)
v0.12.2
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)
v0.12.1
v0.12.1 2017-10-11
Fixed
Constructor#try
rescuesArgumentError
(raised in cases likeInteger('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)