dry-rb / dry-types

Flexible type system for Ruby with coercions and constraints
https://dry-rb.org/gems/dry-types
MIT License
860 stars 134 forks source link

Add `#or_nil` #409

Closed ianks closed 3 years ago

ianks commented 3 years ago

So there have been a few times where it would be nice to simply nullify a value if a type is invalid. Imagine we have this type:

EmailAddress ||= begin
  Types::String
    .constructor(&:downcase)
    .constructor(&:strip)
    .constrained(format: URI::MailTo::EMAIL_REGEXP)
end

Currently, you can use .lax to rescue and return the input: EmailAddress.lax.call('bad') #=> 'bad'

This is useful, but it would useful to be able to nil out the value, as well. This would make it much easier to filter our junky data that’s is not business critical.

This PR adds #or_nil to support this exact use case

EmailAddress.or_nil.call('test@test.com') #=> 'test@test.com'`
EmailAddress.or_nil.call('bad') #=> nil`

via: https://discourse.dry-rb.org/t/something-like-lax-but-return-nil-instead-of-input/1168/2

solnic commented 3 years ago

@ianks I'm so sorry but I didn't see @flash-gordon's reply right here: https://discourse.dry-rb.org/t/something-like-lax-but-return-nil-instead-of-input/1168/5 before I suggested OrNil could be a good addition. Could you please sync up with Nikita about it? From what I now know, he started working on something that will simply support what you need too, and will be more generic.

ianks commented 3 years ago

Would it be possible to merge this PR @flash-gordon / @solnic? Then the refactoring can make this feature work with it? This functionality is critical for us and wouldn't want to have to delay it a lot if that can be avoided.

flash-gordon commented 3 years ago

@ianks can you pin your dependency to this branch maybe?

flash-gordon commented 3 years ago

Now in master it can be done with

Dry::Types.define_builder(:or_nil) { _1.optional.fallback(nil) }

🎉