Custom types using dry-logic and predicates
I wanted to have a custom type in my application for IP addresses - IPv4 and IPv6 types.
My first idea was build the custom type based on top of Dry::Types::Strict::String.constrained
Having a quick look at the constrained type, I realised that its dry-logic that dictates the predicate logic. Another quick search over the Github issues, and I see that I am not the only one who wanted something similar. I found a similar issue that I was trying to solve.
Solution
use the case?
predicate.
From the Github issue:
Anything that responds to===
can be used, including strings, numbers, classes, ranges, regexes, and even procs.
So the case?
predicate responds to ===
, You can pass a pattern and the predicate will check if the pattern matches your input, just what I wanted.
module Types
include Dry.Types
ipv4 = ->(input) { IpValidator.valid_ipv4?(input) }
IPv4 = Types::String.constrained(case: ipv4)
ipv6 = ->(input) { IpValidator.valid_ipv6?(input) }
IPv6 = Types::String.constrained(case: ipv6)
end
In the above snipped, I have an ipv4
and ipv6
lambda which takes an input and checks whether its a valid ipv4
or ipv6
using IpValidator
class, which is a wrapper to check the IP address.
With these 2 lambdas, I can now build my custom types by passing them to the case?
predicate which will check if the input and the pattern matches.
Simple usage:
Types::IPv4.call('127.0.0.1')
Types::IPv6.call('2001:0db8:85a3:0000:0000:8a2e:0370:7334')
Hope that helps someone. Enjoy.!