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