Class: Philiprehberger::SchemaValidator::Schema
- Inherits:
-
Object
- Object
- Philiprehberger::SchemaValidator::Schema
- Includes:
- Constraints
- Defined in:
- lib/philiprehberger/schema_validator/schema.rb
Constant Summary collapse
- TYPES =
%i[string integer float boolean array hash].freeze
Class Method Summary collapse
-
.omit(base, *field_names) ⇒ Schema
Create a sub-schema excluding the specified fields.
-
.pick(base, *field_names) ⇒ Schema
Create a sub-schema with only the specified fields.
Instance Method Summary collapse
-
#depends_on(field, when_field:) ⇒ Object
Declare a conditional field dependency.
-
#exclusive_group(name, fields) ⇒ Object
Declare mutually exclusive fields.
- #fields ⇒ Object
-
#initialize(&block) ⇒ Schema
constructor
A new instance of Schema.
- #merge(&block) ⇒ Object
- #nested(name, **opts) ⇒ Object
-
#strict! ⇒ void
Enable strict mode — unknown keys in validated data will produce errors.
-
#strict? ⇒ Boolean
Whether this schema rejects unknown keys.
-
#to_json_schema ⇒ Hash
Export a simplified JSON Schema (draft 7) representation.
- #validate(data = nil, &block) ⇒ Object
- #validate!(data) ⇒ Object
-
#validate_and_coerce(data) ⇒ Hash{Symbol => Object}
Validate and coerce in a single call.
Constructor Details
#initialize(&block) ⇒ Schema
Returns a new instance of Schema.
12 13 14 15 16 17 18 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 12 def initialize(&block) @fields = {} @nested_schemas = {} @cross_validators = [] @strict = false instance_eval(&block) if block end |
Class Method Details
.omit(base, *field_names) ⇒ Schema
Create a sub-schema excluding the specified fields
75 76 77 78 79 80 81 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 75 def self.omit(base, *field_names) new_schema = new {} # rubocop:disable Lint/EmptyBlock base.instance_variable_get(:@fields).each do |name, field| new_schema.instance_variable_get(:@fields)[name] = field unless field_names.include?(name) end new_schema end |
.pick(base, *field_names) ⇒ Schema
Create a sub-schema with only the specified fields
62 63 64 65 66 67 68 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 62 def self.pick(base, *field_names) new_schema = new {} # rubocop:disable Lint/EmptyBlock base.instance_variable_get(:@fields).each do |name, field| new_schema.instance_variable_get(:@fields)[name] = field if field_names.include?(name) end new_schema end |
Instance Method Details
#depends_on(field, when_field:) ⇒ Object
Declare a conditional field dependency
45 46 47 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 45 def depends_on(field, when_field:) (@dependencies ||= []) << { field: field, when_field: when_field } end |
#exclusive_group(name, fields) ⇒ Object
Declare mutually exclusive fields
53 54 55 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 53 def exclusive_group(name, fields) (@exclusive_groups ||= []) << { name: name, fields: fields } end |
#fields ⇒ Object
130 131 132 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 130 def fields @fields.keys end |
#merge(&block) ⇒ Object
160 161 162 163 164 165 166 167 168 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 160 def merge(&block) new_schema = Schema.new new_schema.instance_variable_set(:@fields, @fields.dup) new_schema.instance_variable_set(:@nested_schemas, @nested_schemas.dup) new_schema.instance_variable_set(:@cross_validators, @cross_validators.dup) new_schema.instance_variable_set(:@strict, @strict) new_schema.instance_eval(&block) if block new_schema end |
#nested(name, **opts) ⇒ Object
83 84 85 86 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 83 def nested(name, **opts, &) sub_schema = Schema.new(&) @nested_schemas[name] = { schema: sub_schema, required: opts.fetch(:required, false) } end |
#strict! ⇒ void
This method returns an undefined value.
Enable strict mode — unknown keys in validated data will produce errors
30 31 32 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 30 def strict! @strict = true end |
#strict? ⇒ Boolean
Whether this schema rejects unknown keys
37 38 39 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 37 def strict? @strict == true end |
#to_json_schema ⇒ Hash
Export a simplified JSON Schema (draft 7) representation
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 137 def to_json_schema properties = {} required_fields = [] @fields.each do |name, field| properties[name.to_s] = field_to_json_schema(field) required_fields << name.to_s if field.required? end @nested_schemas.each do |name, config| properties[name.to_s] = config[:schema].to_json_schema required_fields << name.to_s if config[:required] end schema = { 'type' => 'object', 'properties' => properties } schema['required'] = required_fields unless required_fields.empty? schema['additionalProperties'] = false if strict? schema end |
#validate(data = nil, &block) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 88 def validate(data = nil, &block) if block @cross_validators << block return end errors = [] @fields.each_value { |field| validate_field(field, data, errors) } @nested_schemas.each { |name, config| validate_nested(name, config, data, errors) } @cross_validators.each { |cv| cv.call(data, errors) } validate_unknown_keys(data, errors) if strict? result = Result.new(errors: errors) validate_dependencies(data, result) if @dependencies&.any? validate_exclusive_groups(data, result) if @exclusive_groups&.any? result end |
#validate!(data) ⇒ Object
105 106 107 108 109 110 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 105 def validate!(data) result = validate(data) raise ValidationError, result.errors.join(', ') unless result.valid? result end |
#validate_and_coerce(data) ⇒ Hash{Symbol => Object}
Validate and coerce in a single call
Attempts type coercion on any field whose coercion is well defined and succeeds, leaving other values as provided. Defaults are applied for absent fields. Returns a hash containing the validity flag, the (best-effort) coerced payload, and the error list from ‘#validate`.
120 121 122 123 124 125 126 127 128 |
# File 'lib/philiprehberger/schema_validator/schema.rb', line 120 def validate_and_coerce(data) coerced = begin coerce_payload(data) rescue StandardError data end result = validate(coerced) { valid: result.valid?, values: coerced, errors: result.errors } end |