dry-types

v1.8 v1.7
  1. Introduction
  2. Getting Started
  3. Built-in Types
  4. Type Attributes
  5. Default Values
  6. Fallbacks
  7. Constraints
  8. Hash Schemas
  9. Array With Member
  10. Enum
  11. Map
  12. Combining Types
    1. Intersection
    2. Sum
  13. Custom Types
  14. Custom Type Builders
  15. Extensions
    1. Maybe
    2. Monads

TOC

  1. Example usage
  2. Features
  3. Use cases
  4. Other gems using dry-types

Introduction

dry-types is a simple and extendable type system for Ruby; useful for value coercions, applying constraints, defining complex structs or value objects and more. It was created as a successor to Virtus.

Example usage

require 'dry-types'
require 'dry-struct'

module Types
  include Dry.Types()
end

User = Dry.Struct(name: Types::String, age: Types::Integer)

User.new(name: 'Bob', age: 35)
# => #<User name="Bob" age=35>

See Built-in Types for a full list of available types.

By themselves, the basic type definitions like Types::String and Types::Integer don't do anything except provide documentation about which type an attribute is expected to have. However, there are many more advanced possibilities:

class User < Dry::Struct
  attribute :name, Types::Strict::String
  attribute :age,  Types::Strict::Integer
end

User.new(name: 'Bob', age: '18')
# => Dry::Struct::Error: [User.new] "18" (String) has invalid type for :age
class User < Dry::Struct
  attribute :name, Types::Coercible::String
  attribute :age,  Types::Coercible::Integer
end

User.new(name: 'Bob', age: '18')
# => #<User name="Bob" age=18>
User.new(name: 'Bob', age: 'not coercible')
# => ArgumentError: invalid value for Integer(): "not coercible"
class User < Dry::Struct
  attribute :name, Types::String
  attribute :age,  Types::Integer.optional
end

User.new(name: 'Bob', age: nil)
# => #<User name="Bob" age=nil>
# name is not optional:
User.new(name: nil, age: 18)
# => Dry::Struct::Error: [User.new] nil (NilClass) has invalid type for :name
# keys must still be present:
User.new(name: 'Bob')
# => Dry::Struct::Error: [User.new] :age is missing in Hash input
class User < Dry::Struct
  attribute :name, Types::Strict::String
  attribute :age,  Types::Strict::Integer.constrained(gteq: 18)
end

User.new(name: 'Bob', age: 17)
# => Dry::Struct::Error: [User.new] 17 (Fixnum) has invalid type for :age
class User < Dry::Struct
  attribute :name, Types::String
  attribute :age,  Types::Integer.meta(info: 'extra info about age')
end

User.schema.key(:age).meta
# => {:info=>"extra info about age"}
Types::Strict::String["foo"]
# => "foo"
Types::Strict::String["10000"]
# => "10000"
Types::Coercible::String[10000]
# => "10000"
Types::Strict::String[10000]
# Dry::Types::ConstraintError: 1000 violates constraints

Features

Use cases

dry-types is suitable for many use-cases, for example:

Other gems using dry-types

dry-types is often used as a low-level abstraction. The following gems use it already: