hash_validator 1.1.1 → 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/.github/workflows/ruby.yml +1 -1
- data/.ruby-version +1 -1
- data/README.md +315 -56
- data/hash_validator.gemspec +1 -1
- data/lib/hash_validator/configuration.rb +16 -0
- data/lib/hash_validator/validators/alpha_validator.rb +15 -0
- data/lib/hash_validator/validators/alphanumeric_validator.rb +15 -0
- 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 +15 -0
- 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 +8 -3
- data/lib/hash_validator/validators/hex_color_validator.rb +15 -0
- 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 +21 -0
- 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 +21 -0
- data/lib/hash_validator/validators.rb +46 -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/alpha_validator_spec.rb +93 -0
- data/spec/validators/alphanumeric_validator_spec.rb +99 -0
- data/spec/validators/base_spec.rb +2 -2
- data/spec/validators/digits_validator_spec.rb +99 -0
- data/spec/validators/dynamic_func_validator_spec.rb +252 -0
- data/spec/validators/dynamic_pattern_validator_spec.rb +150 -0
- data/spec/validators/hash_validator_spec.rb +102 -0
- data/spec/validators/hex_color_validator_spec.rb +111 -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/json_validator_spec.rb +88 -0
- data/spec/validators/url_validator_spec.rb +75 -0
- data/spec/validators/user_defined_spec.rb +2 -2
- metadata +42 -4
@@ -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)
|
@@ -4,13 +4,18 @@ class HashValidator::Validator::HashValidator < HashValidator::Validator::Base
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def should_validate?(rhs)
|
7
|
-
rhs.is_a?(Hash)
|
7
|
+
rhs.is_a?(Hash) || (defined?(ActionController::Parameters) && rhs.is_a?(ActionController::Parameters))
|
8
8
|
end
|
9
9
|
|
10
10
|
def validate(key, value, validations, errors)
|
11
|
+
# Convert ActionController::Parameters to Hash if needed
|
12
|
+
if !value.is_a?(Hash) && defined?(ActionController::Parameters) && value.is_a?(ActionController::Parameters)
|
13
|
+
value = value.to_unsafe_h
|
14
|
+
end
|
15
|
+
|
11
16
|
# Validate hash
|
12
17
|
unless value.is_a?(Hash)
|
13
|
-
errors[key] =
|
18
|
+
errors[key] = error_message
|
14
19
|
return
|
15
20
|
end
|
16
21
|
|
@@ -33,4 +38,4 @@ class HashValidator::Validator::HashValidator < HashValidator::Validator::Base
|
|
33
38
|
end
|
34
39
|
|
35
40
|
|
36
|
-
HashValidator.
|
41
|
+
HashValidator.add_validator(HashValidator::Validator::HashValidator.new)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class HashValidator::Validator::HexColorValidator < HashValidator::Validator::Base
|
2
|
+
def initialize
|
3
|
+
super('hex_color') # The name of the validator
|
4
|
+
end
|
5
|
+
|
6
|
+
def error_message
|
7
|
+
'is not a valid hex color'
|
8
|
+
end
|
9
|
+
|
10
|
+
def valid?(value)
|
11
|
+
value.is_a?(String) && /\A#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/.match?(value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
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)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class HashValidator::Validator::JsonValidator < HashValidator::Validator::Base
|
4
|
+
def initialize
|
5
|
+
super('json') # The name of the validator
|
6
|
+
end
|
7
|
+
|
8
|
+
def error_message
|
9
|
+
'is not valid JSON'
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(value)
|
13
|
+
return false unless value.is_a?(String)
|
14
|
+
JSON.parse(value)
|
15
|
+
true
|
16
|
+
rescue JSON::ParserError
|
17
|
+
false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
HashValidator.add_validator(HashValidator::Validator::JsonValidator.new)
|
@@ -15,21 +15,18 @@ class HashValidator::Validator::LambdaValidator < HashValidator::Validator::Base
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
18
|
+
def error_message
|
19
19
|
'is not valid'
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
|
24
|
-
errors[key] = presence_error_message
|
25
|
-
end
|
26
|
-
|
22
|
+
def valid?(value, lambda)
|
23
|
+
lambda.call(value)
|
27
24
|
rescue
|
28
|
-
|
25
|
+
false
|
29
26
|
end
|
30
27
|
end
|
31
28
|
|
32
29
|
class HashValidator::Validator::LambdaValidator::InvalidArgumentCount < StandardError
|
33
30
|
end
|
34
31
|
|
35
|
-
HashValidator.
|
32
|
+
HashValidator.add_validator(HashValidator::Validator::LambdaValidator.new)
|
@@ -9,13 +9,13 @@ module HashValidator
|
|
9
9
|
validation.is_a?(Validations::Many)
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def error_message
|
13
13
|
"enumerable required"
|
14
14
|
end
|
15
15
|
|
16
16
|
def validate(key, value, validations, errors)
|
17
17
|
unless value.is_a?(Enumerable)
|
18
|
-
errors[key] =
|
18
|
+
errors[key] = error_message
|
19
19
|
return
|
20
20
|
end
|
21
21
|
|
@@ -37,4 +37,4 @@ module HashValidator
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
HashValidator.
|
40
|
+
HashValidator.add_validator(HashValidator::Validator::ManyValidator.new)
|
@@ -3,15 +3,13 @@ class HashValidator::Validator::PresenceValidator < HashValidator::Validator::Ba
|
|
3
3
|
super('required')
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
6
|
+
def error_message
|
7
7
|
'is required'
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
10
|
+
def valid?(value)
|
11
|
+
!value.nil?
|
14
12
|
end
|
15
13
|
end
|
16
14
|
|
17
|
-
HashValidator.
|
15
|
+
HashValidator.add_validator(HashValidator::Validator::PresenceValidator.new)
|
@@ -7,15 +7,13 @@ class HashValidator::Validator::RegexpValidator < HashValidator::Validator::Base
|
|
7
7
|
rhs.is_a?(Regexp)
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def error_message
|
11
11
|
'does not match regular expression'
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
|
16
|
-
errors[key] = presence_error_message
|
17
|
-
end
|
14
|
+
def valid?(value, regexp)
|
15
|
+
regexp.match(value.to_s)
|
18
16
|
end
|
19
17
|
end
|
20
18
|
|
21
|
-
HashValidator.
|
19
|
+
HashValidator.add_validator(HashValidator::Validator::RegexpValidator.new)
|
@@ -13,5 +13,5 @@
|
|
13
13
|
Time
|
14
14
|
].each do |type|
|
15
15
|
name = type.to_s.gsub(/(.)([A-Z])/,'\1_\2').downcase # ActiveSupport/Inflector#underscore behaviour
|
16
|
-
HashValidator.
|
16
|
+
HashValidator.add_validator(HashValidator::Validator::SimpleValidator.new(name, lambda { |v| v.is_a?(type) }))
|
17
17
|
end
|
@@ -12,9 +12,7 @@ class HashValidator::Validator::SimpleValidator < HashValidator::Validator::Base
|
|
12
12
|
self.lambda = lambda
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
17
|
-
errors[key] = presence_error_message
|
18
|
-
end
|
15
|
+
def valid?(value)
|
16
|
+
lambda.call(value)
|
19
17
|
end
|
20
18
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
class HashValidator::Validator::UrlValidator < HashValidator::Validator::Base
|
4
|
+
def initialize
|
5
|
+
super('url') # The name of the validator
|
6
|
+
end
|
7
|
+
|
8
|
+
def error_message
|
9
|
+
'is not a valid URL'
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(value)
|
13
|
+
return false unless value.is_a?(String)
|
14
|
+
uri = URI.parse(value)
|
15
|
+
%w[http https ftp].include?(uri.scheme)
|
16
|
+
rescue URI::InvalidURIError
|
17
|
+
false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
HashValidator.add_validator(HashValidator::Validator::UrlValidator.new)
|
@@ -2,9 +2,40 @@ module HashValidator
|
|
2
2
|
@@validators = []
|
3
3
|
|
4
4
|
|
5
|
-
def self.
|
6
|
-
|
7
|
-
|
5
|
+
def self.remove_validator(name)
|
6
|
+
name = name.to_s
|
7
|
+
@@validators.reject! { |v| v.name == name }
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.add_validator(*args)
|
11
|
+
validator = case args.length
|
12
|
+
when 1
|
13
|
+
# Instance-based validator (existing behavior)
|
14
|
+
validator_instance = args[0]
|
15
|
+
unless validator_instance.is_a?(HashValidator::Validator::Base)
|
16
|
+
raise StandardError.new('validators need to inherit from HashValidator::Validator::Base')
|
17
|
+
end
|
18
|
+
validator_instance
|
19
|
+
when 2
|
20
|
+
# Dynamic validator with options
|
21
|
+
name = args[0]
|
22
|
+
options = args[1]
|
23
|
+
|
24
|
+
if options.is_a?(Hash)
|
25
|
+
if options[:pattern]
|
26
|
+
# Pattern-based validator
|
27
|
+
HashValidator::Validator::DynamicPatternValidator.new(name, options[:pattern], options[:error_message])
|
28
|
+
elsif options[:func]
|
29
|
+
# Function-based validator
|
30
|
+
HashValidator::Validator::DynamicFuncValidator.new(name, options[:func], options[:error_message])
|
31
|
+
else
|
32
|
+
raise ArgumentError, 'Options hash must contain either :pattern or :func key'
|
33
|
+
end
|
34
|
+
else
|
35
|
+
raise ArgumentError, 'Second argument must be an options hash with :pattern or :func key'
|
36
|
+
end
|
37
|
+
else
|
38
|
+
raise ArgumentError, 'add_validator expects 1 argument (validator instance) or 2 arguments (name, options)'
|
8
39
|
end
|
9
40
|
|
10
41
|
if @@validators.detect { |v| v.name == validator.name }
|
@@ -24,6 +55,8 @@ end
|
|
24
55
|
|
25
56
|
# Load validators
|
26
57
|
require 'hash_validator/validators/base'
|
58
|
+
require 'hash_validator/validators/dynamic_pattern_validator'
|
59
|
+
require 'hash_validator/validators/dynamic_func_validator'
|
27
60
|
require 'hash_validator/validators/simple_validator'
|
28
61
|
require 'hash_validator/validators/class_validator'
|
29
62
|
require 'hash_validator/validators/hash_validator'
|
@@ -37,4 +70,13 @@ require 'hash_validator/validators/lambda_validator'
|
|
37
70
|
require 'hash_validator/validators/optional_validator'
|
38
71
|
require 'hash_validator/validators/many_validator'
|
39
72
|
require 'hash_validator/validators/multiple_validator'
|
40
|
-
require 'hash_validator/validators/array_validator'
|
73
|
+
require 'hash_validator/validators/array_validator'
|
74
|
+
require 'hash_validator/validators/url_validator'
|
75
|
+
require 'hash_validator/validators/json_validator'
|
76
|
+
require 'hash_validator/validators/hex_color_validator'
|
77
|
+
require 'hash_validator/validators/alphanumeric_validator'
|
78
|
+
require 'hash_validator/validators/alpha_validator'
|
79
|
+
require 'hash_validator/validators/digits_validator'
|
80
|
+
require 'hash_validator/validators/ipv4_validator'
|
81
|
+
require 'hash_validator/validators/ipv6_validator'
|
82
|
+
require 'hash_validator/validators/ip_validator'
|
data/lib/hash_validator.rb
CHANGED
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'HashValidator.configure' do
|
4
|
+
describe 'configuration DSL' do
|
5
|
+
after(:each) do
|
6
|
+
# Clean up any validators added during tests
|
7
|
+
HashValidator.remove_validator('test_pattern')
|
8
|
+
HashValidator.remove_validator('test_func')
|
9
|
+
HashValidator.remove_validator('bulk_odd')
|
10
|
+
HashValidator.remove_validator('bulk_even')
|
11
|
+
HashValidator.remove_validator('bulk_palindrome')
|
12
|
+
HashValidator.remove_validator('custom_configured')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'allows adding instance-based validators' do
|
16
|
+
class HashValidator::Validator::CustomConfiguredValidator < HashValidator::Validator::Base
|
17
|
+
def initialize
|
18
|
+
super('custom_configured')
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?(value)
|
22
|
+
value == 'configured'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
HashValidator.configure do |config|
|
27
|
+
config.add_validator HashValidator::Validator::CustomConfiguredValidator.new
|
28
|
+
end
|
29
|
+
|
30
|
+
validator = HashValidator.validate(
|
31
|
+
{ status: 'configured' },
|
32
|
+
{ status: 'custom_configured' }
|
33
|
+
)
|
34
|
+
expect(validator.valid?).to eq true
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'allows adding pattern-based validators' do
|
38
|
+
HashValidator.configure do |config|
|
39
|
+
config.add_validator 'test_pattern',
|
40
|
+
pattern: /\A[A-Z]{3}\z/,
|
41
|
+
error_message: 'must be three uppercase letters'
|
42
|
+
end
|
43
|
+
|
44
|
+
validator = HashValidator.validate(
|
45
|
+
{ code: 'ABC' },
|
46
|
+
{ code: 'test_pattern' }
|
47
|
+
)
|
48
|
+
expect(validator.valid?).to eq true
|
49
|
+
|
50
|
+
validator = HashValidator.validate(
|
51
|
+
{ code: 'abc' },
|
52
|
+
{ code: 'test_pattern' }
|
53
|
+
)
|
54
|
+
expect(validator.valid?).to eq false
|
55
|
+
expect(validator.errors).to eq({ code: 'must be three uppercase letters' })
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'allows adding function-based validators' do
|
59
|
+
HashValidator.configure do |config|
|
60
|
+
config.add_validator 'test_func',
|
61
|
+
func: ->(v) { v.is_a?(Integer) && v > 100 },
|
62
|
+
error_message: 'must be an integer greater than 100'
|
63
|
+
end
|
64
|
+
|
65
|
+
validator = HashValidator.validate(
|
66
|
+
{ score: 150 },
|
67
|
+
{ score: 'test_func' }
|
68
|
+
)
|
69
|
+
expect(validator.valid?).to eq true
|
70
|
+
|
71
|
+
validator = HashValidator.validate(
|
72
|
+
{ score: 50 },
|
73
|
+
{ score: 'test_func' }
|
74
|
+
)
|
75
|
+
expect(validator.valid?).to eq false
|
76
|
+
expect(validator.errors).to eq({ score: 'must be an integer greater than 100' })
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'allows adding multiple validators in one configure block' do
|
80
|
+
HashValidator.configure do |config|
|
81
|
+
config.add_validator 'bulk_odd',
|
82
|
+
pattern: /\A\d*[13579]\z/,
|
83
|
+
error_message: 'must be odd'
|
84
|
+
|
85
|
+
config.add_validator 'bulk_even',
|
86
|
+
pattern: /\A\d*[02468]\z/,
|
87
|
+
error_message: 'must be even'
|
88
|
+
|
89
|
+
config.add_validator 'bulk_palindrome',
|
90
|
+
func: proc { |s| s.to_s == s.to_s.reverse },
|
91
|
+
error_message: 'must be a palindrome'
|
92
|
+
end
|
93
|
+
|
94
|
+
# Test odd validator
|
95
|
+
validator = HashValidator.validate(
|
96
|
+
{ num: '13' },
|
97
|
+
{ num: 'bulk_odd' }
|
98
|
+
)
|
99
|
+
expect(validator.valid?).to eq true
|
100
|
+
|
101
|
+
# Test even validator
|
102
|
+
validator = HashValidator.validate(
|
103
|
+
{ num: '24' },
|
104
|
+
{ num: 'bulk_even' }
|
105
|
+
)
|
106
|
+
expect(validator.valid?).to eq true
|
107
|
+
|
108
|
+
# Test palindrome validator
|
109
|
+
validator = HashValidator.validate(
|
110
|
+
{ word: 'level' },
|
111
|
+
{ word: 'bulk_palindrome' }
|
112
|
+
)
|
113
|
+
expect(validator.valid?).to eq true
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'allows removing validators within configure block' do
|
117
|
+
# First add a validator
|
118
|
+
HashValidator.add_validator 'test_pattern',
|
119
|
+
pattern: /test/,
|
120
|
+
error_message: 'test'
|
121
|
+
|
122
|
+
# Then remove it in configure
|
123
|
+
HashValidator.configure do |config|
|
124
|
+
config.remove_validator 'test_pattern'
|
125
|
+
end
|
126
|
+
|
127
|
+
# Should raise error as validator no longer exists
|
128
|
+
expect {
|
129
|
+
HashValidator.validate({ value: 'test' }, { value: 'test_pattern' })
|
130
|
+
}.to raise_error(StandardError, /Could not find valid validator/)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'works without a block' do
|
134
|
+
expect {
|
135
|
+
HashValidator.configure
|
136
|
+
}.not_to raise_error
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'yields a Configuration instance' do
|
140
|
+
HashValidator.configure do |config|
|
141
|
+
expect(config).to be_a(HashValidator::Configuration)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe 'Rails-style initializer example' do
|
147
|
+
after(:each) do
|
148
|
+
HashValidator.remove_validator('phone')
|
149
|
+
HashValidator.remove_validator('postal_code')
|
150
|
+
HashValidator.remove_validator('age_range')
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'can be used like a Rails initializer' do
|
154
|
+
# This would typically be in config/initializers/hash_validator.rb
|
155
|
+
HashValidator.configure do |config|
|
156
|
+
# Add pattern validators
|
157
|
+
config.add_validator 'phone',
|
158
|
+
pattern: /\A\+?[1-9]\d{1,14}\z/,
|
159
|
+
error_message: 'must be a valid international phone number'
|
160
|
+
|
161
|
+
config.add_validator 'postal_code',
|
162
|
+
pattern: /\A[A-Z0-9]{3,10}\z/i,
|
163
|
+
error_message: 'must be a valid postal code'
|
164
|
+
|
165
|
+
# Add function validator
|
166
|
+
config.add_validator 'age_range',
|
167
|
+
func: ->(age) { age.is_a?(Integer) && age.between?(0, 120) },
|
168
|
+
error_message: 'must be between 0 and 120'
|
169
|
+
end
|
170
|
+
|
171
|
+
# Use the configured validators
|
172
|
+
validator = HashValidator.validate(
|
173
|
+
{
|
174
|
+
phone: '+14155551234',
|
175
|
+
postal_code: 'SW1A1AA',
|
176
|
+
age: 30
|
177
|
+
},
|
178
|
+
{
|
179
|
+
phone: 'phone',
|
180
|
+
postal_code: 'postal_code',
|
181
|
+
age: 'age_range'
|
182
|
+
}
|
183
|
+
)
|
184
|
+
|
185
|
+
expect(validator.valid?).to eq true
|
186
|
+
expect(validator.errors).to be_empty
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
data/spec/hash_validator_spec.rb
CHANGED
@@ -7,20 +7,20 @@ describe HashValidator do
|
|
7
7
|
|
8
8
|
it 'allows validators with unique names' do
|
9
9
|
expect {
|
10
|
-
HashValidator.
|
10
|
+
HashValidator.add_validator(new_validator1)
|
11
11
|
}.to_not raise_error
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'does not allow validators with conflicting names' do
|
15
15
|
expect {
|
16
|
-
HashValidator.
|
17
|
-
HashValidator.
|
16
|
+
HashValidator.add_validator(new_validator2)
|
17
|
+
HashValidator.add_validator(new_validator2)
|
18
18
|
}.to raise_error(StandardError, 'validators need to have unique names')
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'does not allow validators that do not inherit from the base validator class' do
|
22
22
|
expect {
|
23
|
-
HashValidator.
|
23
|
+
HashValidator.add_validator('Not a validator')
|
24
24
|
}.to raise_error(StandardError, 'validators need to inherit from HashValidator::Validator::Base')
|
25
25
|
end
|
26
26
|
end
|