> ## Content Index
> Fetch the complete content index at: https://til.codes/llms.txt
> Use this file to discover other available public pages before exploring further.

# Custom types using dry-logic and predicates
- URL: https://til.codes/custom-types-with-dry-rb-gems/
- Published: 2020-01-20T17:38:59.000Z
- Updated: 2020-01-20T17:38:59.000Z
- Description: Build custom types for IPv4 and IPv6 using dry-logic and predicates.
- Author: Manu Ajith
- Tags: ruby, dryrb, #Import 2024-07-13 21:01

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](https://github.com/dry-rb/dry-logic/blob/master/lib/dry/logic/predicates.rb?ref=til.codes) 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](https://github.com/dry-rb/dry-types/issues/179?ref=til.codes) 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.

```ruby
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:

```ruby
Types::IPv4.call('127.0.0.1')
Types::IPv6.call('2001:0db8:85a3:0000:0000:8a2e:0370:7334')
```

Hope that helps someone. Enjoy.!