Skip to content

DigitalHospital/expectant

Repository files navigation

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

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published