Coercible types constructors discrepancy

Hello,

There seems to be a small discrepancy in how constructors work. My schema always gets arrays as values, even if they have only one element. In some cases I want to grab the first element of an array and coerce it to a type. In any case the type I’m using to extract the first element from an array as a stringified bool looks like this Types::Params::Bool.constructor(&:first) and works just fine:

[21] pry(main)> Types::Params::Bool.constructor(&:first).call(['false'])
=> false
[22] pry(main)> Types::Params::Bool.constructor(&:first).call(['ffalse'])
Dry::Types::CoercionError: ffalse cannot be coerced to false

However the same thing with date doesn’t work:

[20] pry(main)> Types::Params::Date.constructor(&:first).call(['2019-01-05'])
Dry::Types::CoercionError: ["2019-01-05"] is not a string
from /usr/local/bundle/gems/dry-types-1.2.2/lib/dry/types/coercions.rb:47:in `to_date'

Not sure if I’m doing something wrong :slight_smile:

@DawidJanczak this is expected although I’m not suprised it confused you - Types::Params::* are constructor types, so their coercion logic is applied before yours. This means you need to prepend your logic:

[3] pry(main)> Types::Params::Date.prepend(&:first).call(['2019-01-05'])
=> #<Date: 2019-01-05 ((2458489j,0s,0n),+0s,2299161j)>

I’m not sure why it worked for Bool but it could be a bug. I’d have to debug it.

Thank you @solnic, that works! Piggybacking on that how do I handle invalid dates in those situations? Suppose I use the type you defined above in a params block in a schema like so:

MyDateConstructor = Types::Params::Date.prepend(&:first)
optional(:date).filter(size?: 1).value(MyDateConstructor)

when provided with invalid date the schema fails with Dry::Types::CoercionError: invalid date on an input like date: %w[2019-08-FO]. Should I be handling that myself with the mechanism described here https://github.com/dry-rb/dry-types/blob/master/CHANGELOG.md#added-4 or is there another way to approach this?

Also I tried to do the same for Bool (Types::Params::Bool.prepend(&:first)) and that fails with undefined method prepend’ for #Dry::Types::Sum:0x000055aa4531d630` Perhaps that’s where the discrepancy is coming from?

Similar thing happens with String: Types::String.prepend(&:first) throws `undefined method prepend' for #<Dry::Types[Constrained<Nominal<String> rule=[type?(String)]>]>

when provided with invalid date the schema fails with Dry::Types::CoercionError: invalid

Unfortunately you hit a bug. I just reported an issue about: lax on a prepended constructor still raises · Issue #387 · dry-rb/dry-types · GitHub

Thank you! Are the Bool and String examples different bugs as well or something else entirely?

@DawidJanczak it was the same bug. Nikita already fixed it. It will work fine in 1.3.0 - expect a release soon.

Awesome, thank you :slight_smile:

1 Like