Low commit activity in last 3 years
Define configuration schemas with required and optional keys, type constraints, default values, and allowed value lists. Validates hashes and raises descriptive errors.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

philiprehberger-config_validator

Tests Gem Version Last updated

Configuration schema validator with type checking and helpful error messages

Requirements

  • Ruby >= 3.1

Installation

Add to your Gemfile:

gem "philiprehberger-config_validator"

Or install directly:

gem install philiprehberger-config_validator

Usage

require "philiprehberger/config_validator"

schema = Philiprehberger::ConfigValidator.define do
  required :db_url, String
  optional :port, Integer, default: 3000
  required :env, String, one_of: %w[dev staging prod]
end

errors = schema.validate({ db_url: 'postgres://localhost/mydb', env: 'prod' })
# => []

Required Keys

schema = Philiprehberger::ConfigValidator.define do
  required :db_url, String
  required :secret_key, String
end

errors = schema.validate({})
# => ["missing required key 'db_url'", "missing required key 'secret_key'"]

Optional Keys with Defaults

schema = Philiprehberger::ConfigValidator.define do
  optional :port, Integer, default: 3000
  optional :host, String, default: 'localhost'
end

config = {}
schema.validate(config)
config[:port]  # => 3000
config[:host]  # => "localhost"

Allowed Values

schema = Philiprehberger::ConfigValidator.define do
  required :env, String, one_of: %w[dev staging prod]
end

schema.validate({ env: 'test' })
# => ["key 'env' must be one of [\"dev\", \"staging\", \"prod\"], got \"test\""]

Validate with Raise

schema.validate!({ env: 'invalid' })
# => raises Philiprehberger::ConfigValidator::ValidationError

Nested Schemas

schema = Philiprehberger::ConfigValidator.define do
  nested :database do
    required :host, String
    required :port, Integer
    nested :pool do
      required :size, Integer
    end
  end
end

errors = schema.validate({ database: { host: 'localhost', port: 5432, pool: { size: 5 } } })
# => []

Custom Validators

schema = Philiprehberger::ConfigValidator.define do
  required :email, String
  validate_with(:email, message: 'must contain @') { |v| v.include?('@') }
end

schema.validate({ email: 'invalid' })
# => ["key 'email' must contain @"]

Pattern Matching

schema = Philiprehberger::ConfigValidator.define do
  required :code, String
  pattern :code, /\A[A-Z]{3}-\d{4}\z/, message: 'must match format XXX-0000'
end

schema.validate({ code: 'abc' })
# => ["key 'code' must match format XXX-0000"]

Range Validation

schema = Philiprehberger::ConfigValidator.define do
  required :port, Integer
  range :port, min: 1, max: 65535
end

schema.validate({ port: 70000 })
# => ["key 'port' must be <= 65535, got 70000"]

Example Generation

schema = Philiprehberger::ConfigValidator.define do
  required :db_url, String
  optional :port, Integer, default: 3000
  required :env, String, one_of: %w[dev staging prod]
  optional :debug, TrueClass
end

schema.to_example
# => { db_url: "example", port: 3000, env: "dev", debug: false }

Type Coercion from Strings

Useful when config comes from ENV where all values are strings:

schema = Philiprehberger::ConfigValidator.define do
  required :port, Integer
  required :debug, TrueClass
end

config = { port: '8080', debug: 'true' }
schema.coerce(config)
config[:port]   # => 8080 (Integer)
config[:debug]  # => true (Boolean)

schema.validate(config) # => []

Schema Documentation

schema = Philiprehberger::ConfigValidator.define do
  required :db_url, String
  optional :port, Integer, default: 3000
  required :env, String, one_of: %w[dev staging prod]
end

schema.to_doc
# => [
#   { key: :db_url, type: "String", required: true, default: nil, constraints: nil },
#   { key: :port,   type: "Integer", required: false, default: 3000, constraints: nil },
#   { key: :env,    type: "String", required: true, default: nil, constraints: "one of: [\"dev\", ...]" }
# ]

schema.keys  # => [:db_url, :port, :env]

Inline Validation

errors = Philiprehberger::ConfigValidator.validate(config) do
  required :db_url, String
  optional :port, Integer, default: 3000
end

API

Method Description
ConfigValidator.define { ... } Define a configuration schema, returns a Schema
ConfigValidator.validate(config) { ... } Define and validate in one step, returns error array
ConfigValidator.validate!(config) { ... } Define and validate, raises on errors
Schema#required(key, type, one_of:) Define a required key with type and optional constraint
Schema#optional(key, type, default:, one_of:) Define an optional key with default and constraint
Schema#nested(key, required:, &block) Define a nested schema for a hash key
Schema#validate_with(key, message:, &block) Custom predicate validation
Schema#pattern(key, regex, message:) Regex pattern validation for string values
Schema#range(key, min:, max:) Numeric range validation
Schema#to_example Generate a sample config hash from the schema definition
Schema#coerce(config) Coerce string values to expected types (Integer, Float, Boolean)
Schema#to_doc Generate documentation array describing each key
Schema#keys Return all defined key names as symbols
Schema#required_keys Return array of required key names
Schema#optional_keys Return array of optional key names
Schema#validate(config) Validate a config hash, returns array of error strings
Schema#validate!(config) Validate a config hash, raises ValidationError on failure

Development

bundle install
bundle exec rspec
bundle exec rubocop

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT