Class: Philiprehberger::ConfigValidator::Schema
- Inherits:
-
Object
- Object
- Philiprehberger::ConfigValidator::Schema
- Defined in:
- lib/philiprehberger/config_validator/schema.rb
Overview
DSL for defining configuration schemas
Instance Attribute Summary collapse
-
#custom_validators ⇒ Array<Hash>
readonly
Custom predicate validations.
-
#nested_schemas ⇒ Array<Hash>
readonly
Nested schema definitions.
-
#pattern_validators ⇒ Array<Hash>
readonly
Pattern validations.
-
#range_validators ⇒ Array<Hash>
readonly
Range validations.
-
#rules ⇒ Array<Rule>
readonly
The defined rules.
Instance Method Summary collapse
-
#coerce(config) ⇒ Hash
Coerce string values in a config hash to their expected types.
-
#initialize ⇒ Schema
constructor
A new instance of Schema.
-
#keys ⇒ Array<Symbol>
Return all defined key names.
-
#nested(key, required: true) {|Schema| ... } ⇒ void
Define a nested schema for a hash key.
-
#optional(key, type, default: nil, one_of: nil) ⇒ void
Define an optional configuration key.
-
#optional_keys ⇒ Array<Symbol>
Return the array of keys declared as optional.
-
#pattern(key, regex, message: nil) ⇒ void
Define a regex pattern validation for string values.
-
#range(key, min: nil, max: nil) ⇒ void
Define a numeric range validation.
-
#required(key, type, one_of: nil) ⇒ void
Define a required configuration key.
-
#required_keys ⇒ Array<Symbol>
Return the array of keys declared as required.
-
#to_doc ⇒ Array<Hash>
Generate documentation for the schema.
-
#to_example ⇒ Hash
Generate a sample configuration hash from the schema definition.
-
#validate(config) ⇒ Array<String>
Validate a configuration hash against all rules.
-
#validate!(config) ⇒ Hash
Validate a configuration hash and raise on errors.
-
#validate_with(key, message: 'is invalid') {|Object| ... } ⇒ void
Define a custom predicate validation.
Constructor Details
#initialize ⇒ Schema
Returns a new instance of Schema.
22 23 24 25 26 27 28 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 22 def initialize @rules = [] @nested_schemas = [] @custom_validators = [] @pattern_validators = [] @range_validators = [] end |
Instance Attribute Details
#custom_validators ⇒ Array<Hash> (readonly)
Returns custom predicate validations.
14 15 16 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 14 def custom_validators @custom_validators end |
#nested_schemas ⇒ Array<Hash> (readonly)
Returns nested schema definitions.
11 12 13 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 11 def nested_schemas @nested_schemas end |
#pattern_validators ⇒ Array<Hash> (readonly)
Returns pattern validations.
17 18 19 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 17 def pattern_validators @pattern_validators end |
#range_validators ⇒ Array<Hash> (readonly)
Returns range validations.
20 21 22 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 20 def range_validators @range_validators end |
#rules ⇒ Array<Rule> (readonly)
Returns the defined rules.
8 9 10 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 8 def rules @rules end |
Instance Method Details
#coerce(config) ⇒ Hash
Coerce string values in a config hash to their expected types.
Useful when config comes from ENV where all values are strings. Modifies the hash in place and returns it.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 153 def coerce(config) @rules.each do |rule| value = config.key?(rule.key) ? config[rule.key] : config[rule.key.to_s] next unless value.is_a?(String) coerced = coerce_value(value, rule.type) next if coerced.nil? if config.key?(rule.key) config[rule.key] = coerced elsif config.key?(rule.key.to_s) config[rule.key.to_s] = coerced end end config end |
#keys ⇒ Array<Symbol>
Return all defined key names
118 119 120 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 118 def keys @rules.map(&:key) end |
#nested(key, required: true) {|Schema| ... } ⇒ void
This method returns an undefined value.
Define a nested schema for a hash key
57 58 59 60 61 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 57 def nested(key, required: true, &block) child = Schema.new child.instance_eval(&block) @nested_schemas << { key: key, schema: child, required: required } end |
#optional(key, type, default: nil, one_of: nil) ⇒ void
This method returns an undefined value.
Define an optional configuration key
47 48 49 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 47 def optional(key, type, default: nil, one_of: nil) @rules << Rule.new(key, type, required: false, default: default, one_of: one_of) end |
#optional_keys ⇒ Array<Symbol>
Return the array of keys declared as optional.
Includes keys defined via #optional as well as nested schema keys declared with required: false.
140 141 142 143 144 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 140 def optional_keys rule_keys = @rules.reject(&:required).map(&:key) nested_keys = @nested_schemas.reject { |entry| entry[:required] }.map { |entry| entry[:key] } rule_keys + nested_keys end |
#pattern(key, regex, message: nil) ⇒ void
This method returns an undefined value.
Define a regex pattern validation for string values
80 81 82 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 80 def pattern(key, regex, message: nil) @pattern_validators << { key: key, regex: regex, message: || 'does not match expected pattern' } end |
#range(key, min: nil, max: nil) ⇒ void
This method returns an undefined value.
Define a numeric range validation
90 91 92 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 90 def range(key, min: nil, max: nil) @range_validators << { key: key, min: min, max: max } end |
#required(key, type, one_of: nil) ⇒ void
This method returns an undefined value.
Define a required configuration key
36 37 38 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 36 def required(key, type, one_of: nil) @rules << Rule.new(key, type, required: true, one_of: one_of) end |
#required_keys ⇒ Array<Symbol>
128 129 130 131 132 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 128 def required_keys rule_keys = @rules.select(&:required).map(&:key) nested_keys = @nested_schemas.select { |entry| entry[:required] }.map { |entry| entry[:key] } rule_keys + nested_keys end |
#to_doc ⇒ Array<Hash>
Generate documentation for the schema.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 173 def to_doc @rules.map do |rule| constraints = [] constraints << "one of: #{rule.allowed_values.inspect}" if rule.allowed_values&.any? { key: rule.key, type: rule.type.name, required: rule.required, default: rule.default, constraints: constraints.empty? ? nil : constraints.join(', ') } end end |
#to_example ⇒ Hash
Generate a sample configuration hash from the schema definition
Uses defaults where available, first allowed value for one_of constraints, and type-appropriate placeholders for required fields.
100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 100 def to_example result = {} @rules.each do |rule| value = if rule.default rule.default elsif rule.allowed_values&.any? rule.allowed_values.first else placeholder_for(rule.type) end result[rule.key] = value end result end |
#validate(config) ⇒ Array<String>
Validate a configuration hash against all rules
192 193 194 195 196 197 198 199 200 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 192 def validate(config) apply_defaults(config) errors = rules.flat_map { |rule| rule.validate(config) } errors.concat(validate_nested(config)) errors.concat(validate_custom(config)) errors.concat(validate_patterns(config)) errors.concat(validate_ranges(config)) errors end |
#validate!(config) ⇒ Hash
Validate a configuration hash and raise on errors
207 208 209 210 211 212 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 207 def validate!(config) errors = validate(config) raise ValidationError, "Configuration invalid: #{errors.join('; ')}" unless errors.empty? config end |
#validate_with(key, message: 'is invalid') {|Object| ... } ⇒ void
This method returns an undefined value.
Define a custom predicate validation
70 71 72 |
# File 'lib/philiprehberger/config_validator/schema.rb', line 70 def validate_with(key, message: 'is invalid', &block) @custom_validators << { key: key, message: , block: block } end |