philiprehberger-schema_validator 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +128 -0
- data/lib/philiprehberger/schema_validator/constraints.rb +89 -0
- data/lib/philiprehberger/schema_validator/field.rb +20 -8
- data/lib/philiprehberger/schema_validator/formats.rb +15 -0
- data/lib/philiprehberger/schema_validator/schema.rb +44 -41
- data/lib/philiprehberger/schema_validator/version.rb +1 -1
- data/lib/philiprehberger/schema_validator.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d8df4265e7d600d1e257959c9f8241af55300b726ec88d640c5dced38bcf452f
|
|
4
|
+
data.tar.gz: 729098b84f4986fd5bd7a34aabe0dd1908a9174a11b1df7f21917ce9f80ecda9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 808853b4f3a53335d6bb5dec753fed996e192eaac9a346dba9ddae78f8fe5b25d91f7a1e43144a5498b42a8a58d6c70ea478784427f5928e2ba22d3f2df429e7
|
|
7
|
+
data.tar.gz: 34a39d9763676a48031e9202a72e493d3862c2efb405884f9b2017e77364032f00ec1ba50035a84c852d0582ee5f9c00ec53db876ba325acac761ee758c8d79a
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Nested schema validation via `nested` DSL method with recursive error prefixing
|
|
7
|
+
- Array element validation with `of:` option for type-checked elements
|
|
8
|
+
- Array of objects validation with `schema:` option
|
|
9
|
+
- Built-in format presets: `:email`, `:url`, `:uuid`, `:iso8601`, `:phone`
|
|
10
|
+
- Cross-field validation via `validate` block at schema level
|
|
11
|
+
- Schema composition via `merge` method to combine and extend schemas
|
|
12
|
+
|
|
3
13
|
## 0.2.2
|
|
4
14
|
|
|
5
15
|
- Fix rubocop: string interpolation style, ParameterLists cop
|
data/README.md
CHANGED
|
@@ -80,6 +80,32 @@ schema = Philiprehberger::SchemaValidator.define do
|
|
|
80
80
|
end
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
#### Format Presets
|
|
84
|
+
|
|
85
|
+
Use built-in format presets instead of writing regex patterns:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
schema = Philiprehberger::SchemaValidator.define do
|
|
89
|
+
string :email, format: :email
|
|
90
|
+
string :website, format: :url
|
|
91
|
+
string :id, format: :uuid
|
|
92
|
+
string :created_at, format: :iso8601
|
|
93
|
+
string :phone, format: :phone
|
|
94
|
+
end
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Available presets:
|
|
98
|
+
|
|
99
|
+
| Preset | Matches |
|
|
100
|
+
|------------|--------------------------------------------------|
|
|
101
|
+
| `:email` | Basic email format (`user@domain.tld`) |
|
|
102
|
+
| `:url` | HTTP/HTTPS URLs |
|
|
103
|
+
| `:uuid` | UUID v4 format |
|
|
104
|
+
| `:iso8601` | ISO 8601 date and datetime |
|
|
105
|
+
| `:phone` | International phone numbers |
|
|
106
|
+
|
|
107
|
+
Both symbol presets and `Regexp` values are supported for `format:`.
|
|
108
|
+
|
|
83
109
|
#### `in:` — Allowlist Validation
|
|
84
110
|
|
|
85
111
|
```ruby
|
|
@@ -97,6 +123,104 @@ schema = Philiprehberger::SchemaValidator.define do
|
|
|
97
123
|
end
|
|
98
124
|
```
|
|
99
125
|
|
|
126
|
+
### Nested Schema Validation
|
|
127
|
+
|
|
128
|
+
Validate objects within objects using the `nested` DSL method:
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
schema = Philiprehberger::SchemaValidator.define do
|
|
132
|
+
string :name, required: true
|
|
133
|
+
nested :address, required: true do
|
|
134
|
+
string :city, required: true
|
|
135
|
+
string :zip, required: true
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
result = schema.validate({ name: "Alice", address: { city: "Vienna" } })
|
|
140
|
+
result.errors # => ["address.zip is required"]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Nested schemas support all the same field types and options. Nesting can go arbitrarily deep:
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
schema = Philiprehberger::SchemaValidator.define do
|
|
147
|
+
nested :config, required: true do
|
|
148
|
+
nested :database, required: true do
|
|
149
|
+
string :host, required: true
|
|
150
|
+
integer :port, required: true
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Array Element Validation
|
|
157
|
+
|
|
158
|
+
Validate the type of each element in an array with `of:`:
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
schema = Philiprehberger::SchemaValidator.define do
|
|
162
|
+
array :tags, of: :string
|
|
163
|
+
array :scores, of: :integer
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
result = schema.validate({ tags: ["a", "b"], scores: [1, "bad", 3] })
|
|
167
|
+
result.errors # => ["scores[1] must be a integer"]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Validate arrays of objects with `schema:`:
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
address_schema = Philiprehberger::SchemaValidator.define do
|
|
174
|
+
string :city, required: true
|
|
175
|
+
string :zip, required: true
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
schema = Philiprehberger::SchemaValidator.define do
|
|
179
|
+
array :addresses, schema: address_schema
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
result = schema.validate({ addresses: [{ city: "Vienna" }] })
|
|
183
|
+
result.errors # => ["addresses[0].zip is required"]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Cross-Field Validation
|
|
187
|
+
|
|
188
|
+
Add schema-level validation blocks for relational checks between fields:
|
|
189
|
+
|
|
190
|
+
```ruby
|
|
191
|
+
schema = Philiprehberger::SchemaValidator.define do
|
|
192
|
+
integer :min_age, required: false
|
|
193
|
+
integer :max_age, required: false
|
|
194
|
+
|
|
195
|
+
validate do |data, errors|
|
|
196
|
+
if data[:min_age] && data[:max_age] && data[:min_age] > data[:max_age]
|
|
197
|
+
errors << "min_age must be less than or equal to max_age"
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Multiple `validate` blocks can be defined on the same schema.
|
|
204
|
+
|
|
205
|
+
### Schema Composition
|
|
206
|
+
|
|
207
|
+
Combine and extend schemas using `merge`:
|
|
208
|
+
|
|
209
|
+
```ruby
|
|
210
|
+
base = Philiprehberger::SchemaValidator.define do
|
|
211
|
+
string :name, required: true
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
extended = base.merge do
|
|
215
|
+
integer :age, required: false
|
|
216
|
+
string :email, required: true
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
extended.fields # => [:name, :age, :email]
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The original schema is not modified. Nested schemas and cross-field validators are preserved in the merged schema.
|
|
223
|
+
|
|
100
224
|
### Schema Introspection
|
|
101
225
|
|
|
102
226
|
```ruby
|
|
@@ -148,6 +272,10 @@ Validates a hash against the schema. Returns a `Result` object.
|
|
|
148
272
|
|
|
149
273
|
Validates and raises `ValidationError` if invalid.
|
|
150
274
|
|
|
275
|
+
### `Schema#merge(&block)` -> `Schema`
|
|
276
|
+
|
|
277
|
+
Creates a new schema combining the current schema with additional definitions from the block.
|
|
278
|
+
|
|
151
279
|
### `Result#valid?` -> `Boolean`
|
|
152
280
|
|
|
153
281
|
Returns `true` if there are no errors.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Philiprehberger
|
|
4
|
+
module SchemaValidator
|
|
5
|
+
module Constraints
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def check_type(field, value, errors, field_label)
|
|
9
|
+
coerced = Coercer.coerce(value, field.type)
|
|
10
|
+
if coerced.nil?
|
|
11
|
+
errors << "#{field_label} must be #{field.type}"
|
|
12
|
+
else
|
|
13
|
+
check_constraints(field, coerced, errors, field_label)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def check_constraints(field, value, errors, field_label)
|
|
18
|
+
check_format(field, value, errors, field_label)
|
|
19
|
+
check_inclusion(field, value, errors, field_label)
|
|
20
|
+
check_range(field, value, errors, field_label)
|
|
21
|
+
check_array_elements(field, value, errors, field_label)
|
|
22
|
+
run_custom_validator(field, value, errors, field_label)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def check_format(field, value, errors, field_label)
|
|
26
|
+
return unless field.format
|
|
27
|
+
|
|
28
|
+
pattern = resolve_format(field.format)
|
|
29
|
+
errors << "#{field_label} does not match expected format" unless value.match?(pattern)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def resolve_format(fmt)
|
|
33
|
+
return fmt if fmt.is_a?(Regexp)
|
|
34
|
+
|
|
35
|
+
Formats::FORMATS.fetch(fmt) do
|
|
36
|
+
raise ArgumentError, "unknown format preset: #{fmt}"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def check_inclusion(field, value, errors, field_label)
|
|
41
|
+
return unless field.in
|
|
42
|
+
|
|
43
|
+
errors << "#{field_label} must be one of: #{field.in.join(', ')}" unless field.in.include?(value)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def check_range(field, value, errors, field_label)
|
|
47
|
+
errors << "#{field_label} must be >= #{field.min}" if field.min && value < field.min
|
|
48
|
+
errors << "#{field_label} must be <= #{field.max}" if field.max && value > field.max
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def check_array_elements(field, value, errors, field_label)
|
|
52
|
+
return unless field.type == :array && value.is_a?(Array)
|
|
53
|
+
|
|
54
|
+
if field.of
|
|
55
|
+
validate_array_of_type(field, value, errors, field_label)
|
|
56
|
+
elsif field.schema
|
|
57
|
+
validate_array_of_schema(field, value, errors, field_label)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def validate_array_of_type(field, value, errors, field_label)
|
|
62
|
+
value.each_with_index do |elem, idx|
|
|
63
|
+
coerced = Coercer.coerce(elem, field.of)
|
|
64
|
+
errors << "#{field_label}[#{idx}] must be a #{field.of}" if coerced.nil?
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def validate_array_of_schema(field, value, errors, field_label)
|
|
69
|
+
value.each_with_index do |elem, idx|
|
|
70
|
+
unless elem.is_a?(Hash)
|
|
71
|
+
errors << "#{field_label}[#{idx}] must be a hash"
|
|
72
|
+
next
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
field.schema.validate(elem).errors.each do |err|
|
|
76
|
+
errors << "#{field_label}[#{idx}].#{err}"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def run_custom_validator(field, value, errors, field_label)
|
|
82
|
+
return unless field.validator
|
|
83
|
+
|
|
84
|
+
msg = field.validator.call(value)
|
|
85
|
+
errors << "#{field_label} #{msg}" if msg.is_a?(String)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -3,22 +3,34 @@
|
|
|
3
3
|
module Philiprehberger
|
|
4
4
|
module SchemaValidator
|
|
5
5
|
class Field
|
|
6
|
-
attr_reader :name, :type, :default, :validator, :format, :in, :min, :max
|
|
6
|
+
attr_reader :name, :type, :default, :validator, :format, :in, :min, :max, :of, :schema
|
|
7
7
|
|
|
8
|
-
def initialize(name, type, required: true, default: nil, format: nil, in: nil, min: nil, max: nil, &validator) # rubocop:disable Metrics/ParameterLists
|
|
8
|
+
def initialize(name, type, required: true, default: nil, format: nil, in: nil, min: nil, max: nil, of: nil, schema: nil, &validator) # rubocop:disable Metrics/ParameterLists,Layout/LineLength
|
|
9
|
+
assign_basic_attrs(name, type, required, default, format)
|
|
10
|
+
assign_constraint_attrs(binding.local_variable_get(:in), min, max, of, schema)
|
|
11
|
+
@validator = validator
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def required?
|
|
15
|
+
@required
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def assign_basic_attrs(name, type, required, default, format)
|
|
9
21
|
@name = name
|
|
10
22
|
@type = type
|
|
11
23
|
@required = required
|
|
12
24
|
@default = default
|
|
13
25
|
@format = format
|
|
14
|
-
@in = binding.local_variable_get(:in)
|
|
15
|
-
@min = min
|
|
16
|
-
@max = max
|
|
17
|
-
@validator = validator
|
|
18
26
|
end
|
|
19
27
|
|
|
20
|
-
def
|
|
21
|
-
@
|
|
28
|
+
def assign_constraint_attrs(inclusion, min, max, of, schema)
|
|
29
|
+
@in = inclusion
|
|
30
|
+
@min = min
|
|
31
|
+
@max = max
|
|
32
|
+
@of = of
|
|
33
|
+
@schema = schema
|
|
22
34
|
end
|
|
23
35
|
end
|
|
24
36
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Philiprehberger
|
|
4
|
+
module SchemaValidator
|
|
5
|
+
module Formats
|
|
6
|
+
FORMATS = {
|
|
7
|
+
email: /\A[^@\s]+@[^@\s]+\.[^@\s]+\z/,
|
|
8
|
+
url: %r{\Ahttps?://[^\s]+\z},
|
|
9
|
+
uuid: /\A[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/i,
|
|
10
|
+
iso8601: /\A\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(.\d+)?(Z|[+-]\d{2}:\d{2})?)?\z/,
|
|
11
|
+
phone: /\A\+?[0-9\s\-().]{7,}\z/
|
|
12
|
+
}.freeze
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -5,10 +5,14 @@ module Philiprehberger
|
|
|
5
5
|
class ValidationError < StandardError; end
|
|
6
6
|
|
|
7
7
|
class Schema
|
|
8
|
+
include Constraints
|
|
9
|
+
|
|
8
10
|
TYPES = %i[string integer float boolean array hash].freeze
|
|
9
11
|
|
|
10
12
|
def initialize(&block)
|
|
11
13
|
@fields = {}
|
|
14
|
+
@nested_schemas = {}
|
|
15
|
+
@cross_validators = []
|
|
12
16
|
instance_eval(&block) if block
|
|
13
17
|
end
|
|
14
18
|
|
|
@@ -19,13 +23,21 @@ module Philiprehberger
|
|
|
19
23
|
end
|
|
20
24
|
end
|
|
21
25
|
|
|
22
|
-
def
|
|
23
|
-
|
|
26
|
+
def nested(name, **opts, &)
|
|
27
|
+
sub_schema = Schema.new(&)
|
|
28
|
+
@nested_schemas[name] = { schema: sub_schema, required: opts.fetch(:required, false) }
|
|
24
29
|
end
|
|
25
30
|
|
|
26
|
-
def validate(data)
|
|
31
|
+
def validate(data = nil, &block)
|
|
32
|
+
if block
|
|
33
|
+
@cross_validators << block
|
|
34
|
+
return
|
|
35
|
+
end
|
|
36
|
+
|
|
27
37
|
errors = []
|
|
28
38
|
@fields.each_value { |field| validate_field(field, data, errors) }
|
|
39
|
+
@nested_schemas.each { |name, config| validate_nested(name, config, data, errors) }
|
|
40
|
+
@cross_validators.each { |cv| cv.call(data, errors) }
|
|
29
41
|
Result.new(errors: errors)
|
|
30
42
|
end
|
|
31
43
|
|
|
@@ -36,13 +48,31 @@ module Philiprehberger
|
|
|
36
48
|
result
|
|
37
49
|
end
|
|
38
50
|
|
|
51
|
+
def fields
|
|
52
|
+
@fields.keys
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def merge(&block)
|
|
56
|
+
new_schema = Schema.new
|
|
57
|
+
new_schema.instance_variable_set(:@fields, @fields.dup)
|
|
58
|
+
new_schema.instance_variable_set(:@nested_schemas, @nested_schemas.dup)
|
|
59
|
+
new_schema.instance_variable_set(:@cross_validators, @cross_validators.dup)
|
|
60
|
+
new_schema.instance_eval(&block) if block
|
|
61
|
+
new_schema
|
|
62
|
+
end
|
|
63
|
+
|
|
39
64
|
private
|
|
40
65
|
|
|
41
66
|
def validate_field(field, data, errors)
|
|
42
67
|
value = fetch_value(field, data)
|
|
43
|
-
|
|
68
|
+
field_label = field.name.to_s
|
|
44
69
|
|
|
45
|
-
|
|
70
|
+
if value.nil?
|
|
71
|
+
errors << "#{field_label} is required" if field.required?
|
|
72
|
+
return
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
check_type(field, value, errors, field_label)
|
|
46
76
|
end
|
|
47
77
|
|
|
48
78
|
def fetch_value(field, data)
|
|
@@ -51,48 +81,21 @@ module Philiprehberger
|
|
|
51
81
|
field.default
|
|
52
82
|
end
|
|
53
83
|
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
end
|
|
84
|
+
def validate_nested(name, config, data, errors)
|
|
85
|
+
value = data[name]
|
|
57
86
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
errors << "#{field.name} must be #{field.type}"
|
|
62
|
-
else
|
|
63
|
-
check_constraints(field, coerced, errors)
|
|
87
|
+
if value.nil?
|
|
88
|
+
errors << "#{name} is required" if config[:required]
|
|
89
|
+
return
|
|
64
90
|
end
|
|
65
|
-
end
|
|
66
91
|
|
|
67
|
-
|
|
68
|
-
check_format(field, value, errors)
|
|
69
|
-
check_inclusion(field, value, errors)
|
|
70
|
-
check_range(field, value, errors)
|
|
71
|
-
run_custom_validator(field, value, errors)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def check_format(field, value, errors)
|
|
75
|
-
return unless field.format
|
|
92
|
+
return errors << "#{name} must be a hash" unless value.is_a?(Hash)
|
|
76
93
|
|
|
77
|
-
|
|
94
|
+
collect_nested_errors(name, config[:schema], value, errors)
|
|
78
95
|
end
|
|
79
96
|
|
|
80
|
-
def
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
errors << "#{field.name} must be one of: #{field.in.join(', ')}" unless field.in.include?(value)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def check_range(field, value, errors)
|
|
87
|
-
errors << "#{field.name} must be >= #{field.min}" if field.min && value < field.min
|
|
88
|
-
errors << "#{field.name} must be <= #{field.max}" if field.max && value > field.max
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def run_custom_validator(field, value, errors)
|
|
92
|
-
return unless field.validator
|
|
93
|
-
|
|
94
|
-
msg = field.validator.call(value)
|
|
95
|
-
errors << "#{field.name} #{msg}" if msg.is_a?(String)
|
|
97
|
+
def collect_nested_errors(name, schema, value, errors)
|
|
98
|
+
schema.validate(value).errors.each { |err| errors << "#{name}.#{err}" }
|
|
96
99
|
end
|
|
97
100
|
end
|
|
98
101
|
end
|
|
@@ -4,6 +4,8 @@ require_relative "schema_validator/version"
|
|
|
4
4
|
require_relative "schema_validator/field"
|
|
5
5
|
require_relative "schema_validator/result"
|
|
6
6
|
require_relative "schema_validator/coercer"
|
|
7
|
+
require_relative "schema_validator/formats"
|
|
8
|
+
require_relative "schema_validator/constraints"
|
|
7
9
|
require_relative "schema_validator/schema"
|
|
8
10
|
|
|
9
11
|
module Philiprehberger
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: philiprehberger-schema_validator
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Philip Rehberger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A zero-dependency Ruby gem for validating hash data against schemas with
|
|
14
14
|
type checking, coercion, required/optional fields, and custom validators.
|
|
@@ -23,7 +23,9 @@ files:
|
|
|
23
23
|
- README.md
|
|
24
24
|
- lib/philiprehberger/schema_validator.rb
|
|
25
25
|
- lib/philiprehberger/schema_validator/coercer.rb
|
|
26
|
+
- lib/philiprehberger/schema_validator/constraints.rb
|
|
26
27
|
- lib/philiprehberger/schema_validator/field.rb
|
|
28
|
+
- lib/philiprehberger/schema_validator/formats.rb
|
|
27
29
|
- lib/philiprehberger/schema_validator/result.rb
|
|
28
30
|
- lib/philiprehberger/schema_validator/schema.rb
|
|
29
31
|
- lib/philiprehberger/schema_validator/version.rb
|