hash_validator 1.2.0 → 2.0.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/README.md +173 -12
- data/lib/hash_validator/configuration.rb +16 -0
- data/lib/hash_validator/validators/alpha_validator.rb +4 -12
- data/lib/hash_validator/validators/alphanumeric_validator.rb +4 -12
- data/lib/hash_validator/validators/array_validator.rb +1 -1
- data/lib/hash_validator/validators/base.rb +28 -3
- data/lib/hash_validator/validators/boolean_validator.rb +3 -5
- data/lib/hash_validator/validators/class_validator.rb +1 -1
- data/lib/hash_validator/validators/digits_validator.rb +4 -12
- data/lib/hash_validator/validators/dynamic_func_validator.rb +26 -0
- data/lib/hash_validator/validators/dynamic_pattern_validator.rb +23 -0
- data/lib/hash_validator/validators/email_validator.rb +4 -6
- data/lib/hash_validator/validators/enumerable_validator.rb +4 -6
- data/lib/hash_validator/validators/hash_validator.rb +2 -2
- data/lib/hash_validator/validators/hex_color_validator.rb +4 -12
- data/lib/hash_validator/validators/ip_validator.rb +22 -0
- data/lib/hash_validator/validators/ipv4_validator.rb +18 -0
- data/lib/hash_validator/validators/ipv6_validator.rb +22 -0
- data/lib/hash_validator/validators/json_validator.rb +4 -11
- data/lib/hash_validator/validators/lambda_validator.rb +5 -8
- data/lib/hash_validator/validators/many_validator.rb +3 -3
- data/lib/hash_validator/validators/multiple_validator.rb +1 -1
- data/lib/hash_validator/validators/optional_validator.rb +1 -1
- data/lib/hash_validator/validators/presence_validator.rb +4 -6
- data/lib/hash_validator/validators/regex_validator.rb +4 -6
- data/lib/hash_validator/validators/simple_type_validators.rb +1 -1
- data/lib/hash_validator/validators/simple_validator.rb +2 -4
- data/lib/hash_validator/validators/url_validator.rb +4 -11
- data/lib/hash_validator/validators.rb +40 -4
- data/lib/hash_validator/version.rb +1 -1
- data/lib/hash_validator.rb +1 -0
- data/spec/configuration_spec.rb +189 -0
- data/spec/hash_validator_spec.rb +4 -4
- data/spec/validators/base_spec.rb +2 -2
- data/spec/validators/dynamic_func_validator_spec.rb +252 -0
- data/spec/validators/dynamic_pattern_validator_spec.rb +150 -0
- data/spec/validators/ip_validator_spec.rb +105 -0
- data/spec/validators/ipv4_validator_spec.rb +99 -0
- data/spec/validators/ipv6_validator_spec.rb +99 -0
- data/spec/validators/user_defined_spec.rb +2 -2
- metadata +20 -3
- data/Plan.md +0 -309
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01246137fa6612aec48d3ebabfb97fa856482f73d0827c520765ad636690cc85
|
4
|
+
data.tar.gz: 4e20f8ad39a7a5f1b4f978d5f832ae30a6896687dc3373d7885c41e637efbad4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6503553a0ec7c997006ac24dc183ddfbda551c2a94daaefff08d40733fbf474f2e99d181feccde06faa2312b9bb0d6d7c5eaac810a5d776dd928b8f21946253
|
7
|
+
data.tar.gz: 7710ce2712a4e67f0e164bd8ca648c4233ecab28e73542fe93b9dbc52cda2a77c1ebb5eee2e22608ca52a398cba0c9c21c99ec744dc155c512a08f751d404d31
|
data/README.md
CHANGED
@@ -55,7 +55,7 @@ validator.errors # => {}
|
|
55
55
|
|
56
56
|
### Failed Validation
|
57
57
|
```ruby
|
58
|
-
validations = {
|
58
|
+
validations = {
|
59
59
|
user: {
|
60
60
|
first_name: 'string',
|
61
61
|
age: 'integer',
|
@@ -63,7 +63,7 @@ validations = {
|
|
63
63
|
}
|
64
64
|
}
|
65
65
|
|
66
|
-
hash = {
|
66
|
+
hash = {
|
67
67
|
user: {
|
68
68
|
first_name: 'James',
|
69
69
|
age: 'thirty', # Should be integer
|
@@ -92,9 +92,9 @@ class UsersController < ApplicationController
|
|
92
92
|
}
|
93
93
|
}
|
94
94
|
}
|
95
|
-
|
95
|
+
|
96
96
|
validator = HashValidator.validate(params, validations)
|
97
|
-
|
97
|
+
|
98
98
|
if validator.valid?
|
99
99
|
user = User.create(params[:user])
|
100
100
|
render json: { user: user }, status: :created
|
@@ -109,7 +109,7 @@ end
|
|
109
109
|
# {
|
110
110
|
# "user": {
|
111
111
|
# "name": "John Doe",
|
112
|
-
# "email": "john@example.com",
|
112
|
+
# "email": "john@example.com",
|
113
113
|
# "age": 30,
|
114
114
|
# "website": "https://johndoe.com",
|
115
115
|
# "preferences": {
|
@@ -137,6 +137,9 @@ Define a validation hash which will be used to validate. This hash can be nested
|
|
137
137
|
| `float` | `{ price: 'float' }` | `{ price: 19.99 }` |
|
138
138
|
| `hex_color` | `{ color: 'hex_color' }` | `{ color: '#ff0000' }` |
|
139
139
|
| `integer` | `{ age: 'integer' }` | `{ age: 25 }` |
|
140
|
+
| `ip` | `{ address: 'ip' }` | `{ address: '192.168.1.1' }` |
|
141
|
+
| `ipv4` | `{ address: 'ipv4' }` | `{ address: '10.0.0.1' }` |
|
142
|
+
| `ipv6` | `{ address: 'ipv6' }` | `{ address: '2001:db8::1' }` |
|
140
143
|
| `json` | `{ config: 'json' }` | `{ config: '{"theme": "dark"}' }` |
|
141
144
|
| `numeric` | `{ score: 'numeric' }` | `{ score: 95.5 }` |
|
142
145
|
| `range` | `{ priority: 1..10 }` | `{ priority: 5 }` |
|
@@ -202,7 +205,11 @@ This is particularly useful when combining built-in validators with custom valid
|
|
202
205
|
|
203
206
|
## Custom Validations
|
204
207
|
|
205
|
-
Allows custom defined validations (must inherit from `HashValidator::Validator::Base`).
|
208
|
+
Allows custom defined validations (must inherit from `HashValidator::Validator::Base`).
|
209
|
+
|
210
|
+
### Simple Example (using `valid?`)
|
211
|
+
|
212
|
+
For simple boolean validations, implement the `valid?` method:
|
206
213
|
|
207
214
|
```ruby
|
208
215
|
# Define our custom validator
|
@@ -211,22 +218,176 @@ class HashValidator::Validator::OddValidator < HashValidator::Validator::Base
|
|
211
218
|
super('odd') # The name of the validator
|
212
219
|
end
|
213
220
|
|
214
|
-
def
|
215
|
-
|
216
|
-
|
217
|
-
|
221
|
+
def error_message
|
222
|
+
'must be an odd number'
|
223
|
+
end
|
224
|
+
|
225
|
+
def valid?(value)
|
226
|
+
value.is_a?(Integer) && value.odd?
|
218
227
|
end
|
219
228
|
end
|
220
229
|
|
221
230
|
# Add the validator
|
222
|
-
HashValidator.
|
231
|
+
HashValidator.add_validator(HashValidator::Validator::OddValidator.new)
|
223
232
|
|
224
|
-
# Now the validator can be used!
|
233
|
+
# Now the validator can be used!
|
225
234
|
validator = HashValidator.validate({ age: 27 }, { age: 'odd' })
|
226
235
|
validator.valid? # => true
|
227
236
|
validator.errors # => {}
|
237
|
+
|
238
|
+
validator = HashValidator.validate({ age: 26 }, { age: 'odd' })
|
239
|
+
validator.valid? # => false
|
240
|
+
validator.errors # => { age: 'must be an odd number' }
|
228
241
|
```
|
229
242
|
|
243
|
+
### Complex Example (using `validate`)
|
244
|
+
|
245
|
+
For more complex validations that need access to the validation parameters or custom error handling, override the `validate` method:
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
# Define a validator that checks if a number is within a range
|
249
|
+
class HashValidator::Validator::RangeValidator < HashValidator::Validator::Base
|
250
|
+
def initialize
|
251
|
+
super('_range') # Underscore prefix as it's invoked through the validation parameter
|
252
|
+
end
|
253
|
+
|
254
|
+
def should_validate?(validation)
|
255
|
+
validation.is_a?(Range)
|
256
|
+
end
|
257
|
+
|
258
|
+
def error_message
|
259
|
+
'is out of range'
|
260
|
+
end
|
261
|
+
|
262
|
+
def validate(key, value, range, errors)
|
263
|
+
unless range.include?(value)
|
264
|
+
errors[key] = "must be between #{range.min} and #{range.max}"
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
# Add the validator
|
270
|
+
HashValidator.add_validator(HashValidator::Validator::RangeValidator.new)
|
271
|
+
|
272
|
+
# Now the validator can be used with Range objects!
|
273
|
+
validator = HashValidator.validate({ age: 25 }, { age: 18..65 })
|
274
|
+
validator.valid? # => true
|
275
|
+
validator.errors # => {}
|
276
|
+
|
277
|
+
validator = HashValidator.validate({ age: 10 }, { age: 18..65 })
|
278
|
+
validator.valid? # => false
|
279
|
+
validator.errors # => { age: 'must be between 18 and 65' }
|
280
|
+
```
|
281
|
+
|
282
|
+
## Simple Custom Validators
|
283
|
+
|
284
|
+
For simpler use cases, you can define custom validators without creating a full class using pattern matching or custom functions.
|
285
|
+
|
286
|
+
### Configuration DSL
|
287
|
+
|
288
|
+
Use the configuration DSL to define multiple validators at once, similar to a Rails initializer:
|
289
|
+
|
290
|
+
```ruby
|
291
|
+
# In a Rails app, this would go in config/initializers/hash_validator.rb
|
292
|
+
HashValidator.configure do |config|
|
293
|
+
# Add instance-based validators
|
294
|
+
config.add_validator HashValidator::Validator::CustomValidator.new
|
295
|
+
|
296
|
+
# Add pattern-based validators
|
297
|
+
config.add_validator 'phone',
|
298
|
+
pattern: /\A\+?[1-9]\d{1,14}\z/,
|
299
|
+
error_message: 'must be a valid international phone number'
|
300
|
+
|
301
|
+
config.add_validator 'postal_code',
|
302
|
+
pattern: /\A[A-Z0-9]{3,10}\z/i,
|
303
|
+
error_message: 'must be a valid postal code'
|
304
|
+
|
305
|
+
# Add function-based validators
|
306
|
+
config.add_validator 'adult',
|
307
|
+
func: ->(age) { age.is_a?(Integer) && age >= 18 },
|
308
|
+
error_message: 'must be 18 or older'
|
309
|
+
|
310
|
+
config.add_validator 'business_hours',
|
311
|
+
func: ->(hour) { hour.between?(9, 17) },
|
312
|
+
error_message: 'must be between 9 AM and 5 PM'
|
313
|
+
end
|
314
|
+
```
|
315
|
+
|
316
|
+
### Pattern-Based Validators
|
317
|
+
|
318
|
+
Use regular expressions to validate string formats:
|
319
|
+
|
320
|
+
```ruby
|
321
|
+
# Add a validator for odd numbers using a pattern
|
322
|
+
HashValidator.add_validator('odd_string',
|
323
|
+
pattern: /\A\d*[13579]\z/,
|
324
|
+
error_message: 'must be an odd number string')
|
325
|
+
|
326
|
+
# Add a validator for US phone numbers
|
327
|
+
HashValidator.add_validator('us_phone',
|
328
|
+
pattern: /\A\d{3}-\d{3}-\d{4}\z/,
|
329
|
+
error_message: 'must be a valid US phone number (XXX-XXX-XXXX)')
|
330
|
+
|
331
|
+
# Use the validators
|
332
|
+
validator = HashValidator.validate(
|
333
|
+
{ number: '27', phone: '555-123-4567' },
|
334
|
+
{ number: 'odd_string', phone: 'us_phone' }
|
335
|
+
)
|
336
|
+
validator.valid? # => true
|
337
|
+
|
338
|
+
validator = HashValidator.validate(
|
339
|
+
{ number: '26', phone: '5551234567' },
|
340
|
+
{ number: 'odd_string', phone: 'us_phone' }
|
341
|
+
)
|
342
|
+
validator.valid? # => false
|
343
|
+
validator.errors # => { number: 'must be an odd number string', phone: 'must be a valid US phone number (XXX-XXX-XXXX)' }
|
344
|
+
```
|
345
|
+
|
346
|
+
### Function-Based Validators
|
347
|
+
|
348
|
+
Use lambdas or procs for custom validation logic:
|
349
|
+
|
350
|
+
```ruby
|
351
|
+
# Add a validator for adult age using a lambda
|
352
|
+
HashValidator.add_validator('adult_age',
|
353
|
+
func: ->(age) { age.is_a?(Integer) && age >= 18 },
|
354
|
+
error_message: 'must be 18 or older')
|
355
|
+
|
356
|
+
# Add a validator for palindromes using a proc
|
357
|
+
HashValidator.add_validator('palindrome',
|
358
|
+
func: proc { |str| str.to_s == str.to_s.reverse },
|
359
|
+
error_message: 'must be a palindrome')
|
360
|
+
|
361
|
+
# Use the validators
|
362
|
+
validator = HashValidator.validate(
|
363
|
+
{ age: 25, word: 'racecar' },
|
364
|
+
{ age: 'adult_age', word: 'palindrome' }
|
365
|
+
)
|
366
|
+
validator.valid? # => true
|
367
|
+
|
368
|
+
validator = HashValidator.validate(
|
369
|
+
{ age: 16, word: 'hello' },
|
370
|
+
{ age: 'adult_age', word: 'palindrome' }
|
371
|
+
)
|
372
|
+
validator.valid? # => false
|
373
|
+
validator.errors # => { age: 'must be 18 or older', word: 'must be a palindrome' }
|
374
|
+
```
|
375
|
+
|
376
|
+
### Removing Custom Validators
|
377
|
+
|
378
|
+
You can remove custom validators when they're no longer needed:
|
379
|
+
|
380
|
+
```ruby
|
381
|
+
# Remove a specific validator
|
382
|
+
HashValidator.remove_validator('adult_age')
|
383
|
+
```
|
384
|
+
|
385
|
+
These simple validators are ideal for:
|
386
|
+
- Quick format validation without regex in your main code
|
387
|
+
- Reusable validation logic across your application
|
388
|
+
- Keeping validation definitions close to your configuration
|
389
|
+
- Avoiding the overhead of creating full validator classes for simple rules
|
390
|
+
|
230
391
|
## Contributing
|
231
392
|
|
232
393
|
1. Fork it
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module HashValidator
|
2
|
+
class Configuration
|
3
|
+
def add_validator(*args)
|
4
|
+
HashValidator.add_validator(*args)
|
5
|
+
end
|
6
|
+
|
7
|
+
def remove_validator(name)
|
8
|
+
HashValidator.remove_validator(name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.configure
|
13
|
+
config = Configuration.new
|
14
|
+
yield(config) if block_given?
|
15
|
+
end
|
16
|
+
end
|
@@ -3,21 +3,13 @@ class HashValidator::Validator::AlphaValidator < HashValidator::Validator::Base
|
|
3
3
|
super('alpha') # The name of the validator
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
6
|
+
def error_message
|
7
7
|
'must contain only letters'
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def valid_alpha?(value)
|
19
|
-
/\A[a-zA-Z]+\z/.match?(value)
|
10
|
+
def valid?(value)
|
11
|
+
value.is_a?(String) && /\A[a-zA-Z]+\z/.match?(value)
|
20
12
|
end
|
21
13
|
end
|
22
14
|
|
23
|
-
HashValidator.
|
15
|
+
HashValidator.add_validator(HashValidator::Validator::AlphaValidator.new)
|
@@ -3,21 +3,13 @@ class HashValidator::Validator::AlphanumericValidator < HashValidator::Validator
|
|
3
3
|
super('alphanumeric') # The name of the validator
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
6
|
+
def error_message
|
7
7
|
'must contain only letters and numbers'
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def valid_alphanumeric?(value)
|
19
|
-
/\A[a-zA-Z0-9]+\z/.match?(value)
|
10
|
+
def valid?(value)
|
11
|
+
value.is_a?(String) && /\A[a-zA-Z0-9]+\z/.match?(value)
|
20
12
|
end
|
21
13
|
end
|
22
14
|
|
23
|
-
HashValidator.
|
15
|
+
HashValidator.add_validator(HashValidator::Validator::AlphanumericValidator.new)
|
@@ -14,11 +14,36 @@ class HashValidator::Validator::Base
|
|
14
14
|
self.name == name.to_s
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
17
|
+
def error_message
|
18
18
|
"#{self.name} required"
|
19
19
|
end
|
20
20
|
|
21
|
-
def validate(
|
22
|
-
|
21
|
+
def validate(key, value, validations, errors)
|
22
|
+
# If the subclass implements valid?, use that for simple boolean validation
|
23
|
+
if self.class.instance_methods(false).include?(:valid?)
|
24
|
+
# Check the arity of the valid? method to determine how many arguments to pass
|
25
|
+
valid_result = case method(:valid?).arity
|
26
|
+
when 1
|
27
|
+
valid?(value)
|
28
|
+
when 2
|
29
|
+
valid?(value, validations)
|
30
|
+
else
|
31
|
+
raise StandardError.new("valid? method must accept either 1 argument (value) or 2 arguments (value, validations)")
|
32
|
+
end
|
33
|
+
|
34
|
+
unless valid_result
|
35
|
+
errors[key] = error_message
|
36
|
+
end
|
37
|
+
else
|
38
|
+
# Otherwise, subclass must override validate
|
39
|
+
raise StandardError.new('Validator must implement either valid? or override validate method')
|
40
|
+
end
|
23
41
|
end
|
42
|
+
|
43
|
+
# Subclasses can optionally implement this for simple boolean validation
|
44
|
+
# Return true if valid, false if invalid
|
45
|
+
# Either:
|
46
|
+
# def valid?(value) # For simple validations
|
47
|
+
# def valid?(value, validations) # When validation context is needed
|
48
|
+
# end
|
24
49
|
end
|
@@ -3,11 +3,9 @@ class HashValidator::Validator::BooleanValidator < HashValidator::Validator::Bas
|
|
3
3
|
super('boolean') # The name of the validator
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
errors[key] = presence_error_message
|
9
|
-
end
|
6
|
+
def valid?(value)
|
7
|
+
[TrueClass, FalseClass].include?(value.class)
|
10
8
|
end
|
11
9
|
end
|
12
10
|
|
13
|
-
HashValidator.
|
11
|
+
HashValidator.add_validator(HashValidator::Validator::BooleanValidator.new)
|
@@ -3,21 +3,13 @@ class HashValidator::Validator::DigitsValidator < HashValidator::Validator::Base
|
|
3
3
|
super('digits') # The name of the validator
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
6
|
+
def error_message
|
7
7
|
'must contain only digits'
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def valid_digits?(value)
|
19
|
-
/\A\d+\z/.match?(value)
|
10
|
+
def valid?(value)
|
11
|
+
value.is_a?(String) && /\A\d+\z/.match?(value)
|
20
12
|
end
|
21
13
|
end
|
22
14
|
|
23
|
-
HashValidator.
|
15
|
+
HashValidator.add_validator(HashValidator::Validator::DigitsValidator.new)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class HashValidator::Validator::DynamicFuncValidator < HashValidator::Validator::Base
|
2
|
+
attr_accessor :func, :custom_error_message
|
3
|
+
|
4
|
+
def initialize(name, func, error_message = nil)
|
5
|
+
super(name)
|
6
|
+
|
7
|
+
unless func.respond_to?(:call)
|
8
|
+
raise ArgumentError, "Function must be callable (proc or lambda)"
|
9
|
+
end
|
10
|
+
|
11
|
+
@func = func
|
12
|
+
@custom_error_message = error_message
|
13
|
+
end
|
14
|
+
|
15
|
+
def error_message
|
16
|
+
@custom_error_message || super
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid?(value)
|
20
|
+
begin
|
21
|
+
!!@func.call(value)
|
22
|
+
rescue => e
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class HashValidator::Validator::DynamicPatternValidator < HashValidator::Validator::Base
|
2
|
+
attr_accessor :pattern, :custom_error_message
|
3
|
+
|
4
|
+
def initialize(name, pattern, error_message = nil)
|
5
|
+
super(name)
|
6
|
+
|
7
|
+
unless pattern.is_a?(Regexp)
|
8
|
+
raise ArgumentError, "Pattern must be a regular expression"
|
9
|
+
end
|
10
|
+
|
11
|
+
@pattern = pattern
|
12
|
+
@custom_error_message = error_message
|
13
|
+
end
|
14
|
+
|
15
|
+
def error_message
|
16
|
+
@custom_error_message || super
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid?(value)
|
20
|
+
return false unless value.respond_to?(:to_s)
|
21
|
+
@pattern.match?(value.to_s)
|
22
|
+
end
|
23
|
+
end
|
@@ -3,15 +3,13 @@ class HashValidator::Validator::EmailValidator < HashValidator::Validator::Base
|
|
3
3
|
super('email') # The name of the validator
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
6
|
+
def error_message
|
7
7
|
'is not a valid email'
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
10
|
+
def valid?(value)
|
11
|
+
value.is_a?(String) && value.include?("@")
|
14
12
|
end
|
15
13
|
end
|
16
14
|
|
17
|
-
HashValidator.
|
15
|
+
HashValidator.add_validator(HashValidator::Validator::EmailValidator.new)
|
@@ -7,15 +7,13 @@ class HashValidator::Validator::EnumerableValidator < HashValidator::Validator::
|
|
7
7
|
rhs.is_a?(Enumerable)
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def error_message
|
11
11
|
'value from list required'
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
|
16
|
-
errors[key] = presence_error_message
|
17
|
-
end
|
14
|
+
def valid?(value, validations)
|
15
|
+
validations.include?(value)
|
18
16
|
end
|
19
17
|
end
|
20
18
|
|
21
|
-
HashValidator.
|
19
|
+
HashValidator.add_validator(HashValidator::Validator::EnumerableValidator.new)
|
@@ -15,7 +15,7 @@ class HashValidator::Validator::HashValidator < HashValidator::Validator::Base
|
|
15
15
|
|
16
16
|
# Validate hash
|
17
17
|
unless value.is_a?(Hash)
|
18
|
-
errors[key] =
|
18
|
+
errors[key] = error_message
|
19
19
|
return
|
20
20
|
end
|
21
21
|
|
@@ -38,4 +38,4 @@ class HashValidator::Validator::HashValidator < HashValidator::Validator::Base
|
|
38
38
|
end
|
39
39
|
|
40
40
|
|
41
|
-
HashValidator.
|
41
|
+
HashValidator.add_validator(HashValidator::Validator::HashValidator.new)
|
@@ -3,21 +3,13 @@ class HashValidator::Validator::HexColorValidator < HashValidator::Validator::Ba
|
|
3
3
|
super('hex_color') # The name of the validator
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
6
|
+
def error_message
|
7
7
|
'is not a valid hex color'
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def valid_hex_color?(value)
|
19
|
-
/\A#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/.match?(value)
|
10
|
+
def valid?(value)
|
11
|
+
value.is_a?(String) && /\A#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/.match?(value)
|
20
12
|
end
|
21
13
|
end
|
22
14
|
|
23
|
-
HashValidator.
|
15
|
+
HashValidator.add_validator(HashValidator::Validator::HexColorValidator.new)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
class HashValidator::Validator::IpValidator < HashValidator::Validator::Base
|
4
|
+
def initialize
|
5
|
+
super('ip') # The name of the validator
|
6
|
+
end
|
7
|
+
|
8
|
+
def error_message
|
9
|
+
'is not a valid IP address'
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(value)
|
13
|
+
return false unless value.is_a?(String)
|
14
|
+
# Use IPAddr to validate both IPv4 and IPv6 addresses
|
15
|
+
IPAddr.new(value)
|
16
|
+
true
|
17
|
+
rescue IPAddr::Error, IPAddr::InvalidAddressError
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
HashValidator.add_validator(HashValidator::Validator::IpValidator.new)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class HashValidator::Validator::Ipv4Validator < HashValidator::Validator::Base
|
2
|
+
def initialize
|
3
|
+
super('ipv4') # The name of the validator
|
4
|
+
end
|
5
|
+
|
6
|
+
def error_message
|
7
|
+
'is not a valid IPv4 address'
|
8
|
+
end
|
9
|
+
|
10
|
+
def valid?(value)
|
11
|
+
return false unless value.is_a?(String)
|
12
|
+
# IPv4 regex: 4 octets, each 0-255
|
13
|
+
ipv4_regex = /\A(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\z/
|
14
|
+
value.match?(ipv4_regex)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
HashValidator.add_validator(HashValidator::Validator::Ipv4Validator.new)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
class HashValidator::Validator::Ipv6Validator < HashValidator::Validator::Base
|
4
|
+
def initialize
|
5
|
+
super('ipv6') # The name of the validator
|
6
|
+
end
|
7
|
+
|
8
|
+
def error_message
|
9
|
+
'is not a valid IPv6 address'
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(value)
|
13
|
+
return false unless value.is_a?(String)
|
14
|
+
# Use IPAddr to validate IPv6 addresses (handles standard and compressed notation)
|
15
|
+
addr = IPAddr.new(value)
|
16
|
+
addr.ipv6?
|
17
|
+
rescue IPAddr::Error, IPAddr::InvalidAddressError
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
HashValidator.add_validator(HashValidator::Validator::Ipv6Validator.new)
|
@@ -5,19 +5,12 @@ class HashValidator::Validator::JsonValidator < HashValidator::Validator::Base
|
|
5
5
|
super('json') # The name of the validator
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
8
|
+
def error_message
|
9
9
|
'is not valid JSON'
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
unless value.is_a?(String)
|
14
|
-
errors[key] = presence_error_message
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def valid_json?(value)
|
12
|
+
def valid?(value)
|
13
|
+
return false unless value.is_a?(String)
|
21
14
|
JSON.parse(value)
|
22
15
|
true
|
23
16
|
rescue JSON::ParserError
|
@@ -25,4 +18,4 @@ class HashValidator::Validator::JsonValidator < HashValidator::Validator::Base
|
|
25
18
|
end
|
26
19
|
end
|
27
20
|
|
28
|
-
HashValidator.
|
21
|
+
HashValidator.add_validator(HashValidator::Validator::JsonValidator.new)
|