Project

expectant

0.0
The project is in a healthy, maintained state
Expectant provides a clean DSL for defining multiple validation schemas in a single class. Built on dry-validation and dry-types, it supports custom rules, defaults, fallbacks, and context-aware validations, making it easy to validate inputs, outputs, and any structured data in your Ruby applications.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

 Project Readme

Expectant

Gem Version Ruby Test

A Ruby DSL for defining validation schemas with type coercion, defaults, and fallbacks. Built on dry-validation and dry-types.

Installation

gem 'expectant'

Quick Start

class InvoiceService
  include Expectant::DSL

  expects :inputs

  input :customer_id, type: :integer
  input :amount, type: :float
  input :status, type: :string, default: "draft"
  input :description, type: :string, optional: true

  input_rule(:amount) do
    key.failure("must be positive") if value && value <= 0
  end

  def process(data)
    result = inputs.validate(data)

    if result.success?
      # Use validated data: result.to_h
    else
      # Handle errors: result.errors.to_h
    end
  end
end

Core Features

Types

expects :inputs

input :name, type: :string
input :age, type: :integer
input :price, type: :float
input :active, type: :boolean
input :date, type: :date
input :time, type: :datetime
input :data, type: :hash
input :tags, type: :array
input :user, type: User  # Custom class

Defaults and Optional Fields

# Optional (can be omitted)
input :description, type: :string, optional: true

# Static default
input :status, type: :string, default: "draft"

# Dynamic default (proc)
input :created_at, type: :datetime, default: -> { Time.now }

Fallbacks

Automatically substitute values when validation fails:

input :per_page, type: :integer, default: 25, fallback: 25

input_rule(:per_page) do
  key.failure("max 100") if value && value > 100
end

# If per_page: 500 is provided, validation succeeds with fallback value 25

Validation Rules

# Single field
input_rule(:email) do
  key.failure("invalid") unless value&.include?("@")
end

# Multiple fields
input_rule(:start_date, :end_date) do
  base.failure("start must be before end") if values[:start_date] > values[:end_date]
end

# Global rule
input_rule do
  base.failure("error") if some_condition
end

Context

input_rule(:order) do
  valid = context[:orderable_columns] || []
  key.failure("invalid column") unless valid.include?(value)
end

# Pass context when validating
inputs.validate(data, context: { orderable_columns: ["id", "name"] })

Multiple Schemas

expects :inputs
expects :outputs

input :data, type: :hash
output :result, type: :string

inputs.validate(input_data)
outputs.validate(output_data)

Configuration

Customize validator method names:

Expectant.configure do |config|
  config.validator_suffix = "validation"  # input_validation instead of input_rule
  config.validator_prefix = "validate"    # validate_input
end

Development

bundle install
bundle exec rspec

License

MIT License