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,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module HashValidator
|
2
4
|
module Validations
|
3
5
|
end
|
4
6
|
end
|
5
7
|
|
6
8
|
# Load validators
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
9
|
+
require "hash_validator/validations/optional"
|
10
|
+
require "hash_validator/validations/many"
|
11
|
+
require "hash_validator/validations/multiple"
|
@@ -1,23 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::AlphaValidator < HashValidator::Validator::Base
|
2
4
|
def initialize
|
3
|
-
super(
|
4
|
-
end
|
5
|
-
|
6
|
-
def presence_error_message
|
7
|
-
'must contain only letters'
|
5
|
+
super("alpha") # The name of the validator
|
8
6
|
end
|
9
7
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
8
|
+
def error_message
|
9
|
+
"must contain only letters"
|
14
10
|
end
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
def valid_alpha?(value)
|
19
|
-
/\A[a-zA-Z]+\z/.match?(value)
|
12
|
+
def valid?(value)
|
13
|
+
value.is_a?(String) && /\A[a-zA-Z]+\z/.match?(value)
|
20
14
|
end
|
21
15
|
end
|
22
16
|
|
23
|
-
HashValidator.
|
17
|
+
HashValidator.add_validator(HashValidator::Validator::AlphaValidator.new)
|
@@ -1,23 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::AlphanumericValidator < HashValidator::Validator::Base
|
2
4
|
def initialize
|
3
|
-
super(
|
4
|
-
end
|
5
|
-
|
6
|
-
def presence_error_message
|
7
|
-
'must contain only letters and numbers'
|
5
|
+
super("alphanumeric") # The name of the validator
|
8
6
|
end
|
9
7
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
8
|
+
def error_message
|
9
|
+
"must contain only letters and numbers"
|
14
10
|
end
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
def valid_alphanumeric?(value)
|
19
|
-
/\A[a-zA-Z0-9]+\z/.match?(value)
|
12
|
+
def valid?(value)
|
13
|
+
value.is_a?(String) && /\A[a-zA-Z0-9]+\z/.match?(value)
|
20
14
|
end
|
21
15
|
end
|
22
16
|
|
23
|
-
HashValidator.
|
17
|
+
HashValidator.add_validator(HashValidator::Validator::AlphanumericValidator.new)
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::ArrayValidator < HashValidator::Validator::Base
|
2
4
|
def initialize
|
3
|
-
super(
|
5
|
+
super("__array__") # 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)
|
@@ -8,73 +10,67 @@ class HashValidator::Validator::ArrayValidator < HashValidator::Validator::Base
|
|
8
10
|
return false unless rhs.size > 0
|
9
11
|
return false unless rhs[0] == :array
|
10
12
|
|
11
|
-
|
13
|
+
true
|
12
14
|
end
|
13
15
|
|
14
16
|
def validate(key, value, specification, errors)
|
15
|
-
#
|
16
|
-
|
17
|
+
# Validate specification format
|
18
|
+
if specification[0] != :array
|
17
19
|
errors[key] = "Wrong array specification. The #{:array} is expected as first item."
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
if specification.size > 2
|
20
|
+
elsif specification.size > 2
|
22
21
|
errors[key] = "Wrong size of array specification. Allowed is one or two items."
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
unless value.is_a?(Array)
|
22
|
+
elsif !value.is_a?(Array)
|
27
23
|
errors[key] = "#{Array} required"
|
28
|
-
|
24
|
+
elsif specification.size >= 2 && !specification[1].nil?
|
25
|
+
validate_array_specification(key, value, specification[1], errors)
|
29
26
|
end
|
27
|
+
end
|
30
28
|
|
31
|
-
|
32
|
-
|
29
|
+
private
|
30
|
+
def validate_array_specification(key, value, array_spec, errors)
|
31
|
+
# Convert numeric specification to hash format
|
32
|
+
array_spec = { size: array_spec } if array_spec.is_a?(Numeric)
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
unless array_spec.is_a?(Hash)
|
35
|
+
errors[key] = "Second item of array specification must be #{Hash} or #{Numeric}."
|
36
|
+
return
|
37
|
+
end
|
36
38
|
|
37
|
-
|
38
|
-
array_spec = { size: array_spec }
|
39
|
-
end
|
39
|
+
return if array_spec.empty?
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
return
|
41
|
+
validate_size_specification(key, value, array_spec, errors) if errors.empty?
|
42
|
+
validate_allowed_keys(key, array_spec, errors) if errors.empty?
|
44
43
|
end
|
45
44
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
!!object
|
45
|
+
def validate_size_specification(key, value, array_spec, errors)
|
46
|
+
size_spec = array_spec[:size]
|
47
|
+
|
48
|
+
size_spec_present = case size_spec
|
49
|
+
when String
|
50
|
+
!size_spec.strip.empty?
|
51
|
+
when NilClass
|
52
|
+
false
|
53
|
+
when Numeric
|
54
|
+
true
|
55
|
+
when Array, Hash
|
56
|
+
!size_spec.empty?
|
57
|
+
else
|
58
|
+
!!size_spec
|
61
59
|
end
|
62
60
|
|
63
|
-
|
64
|
-
unless value.size == size_spec
|
61
|
+
if size_spec_present && value.size != size_spec
|
65
62
|
errors[key] = "The required size of array is #{size_spec} but is #{value.size}."
|
66
|
-
return
|
67
63
|
end
|
68
64
|
end
|
69
65
|
|
70
|
-
|
71
|
-
|
66
|
+
def validate_allowed_keys(key, array_spec, errors)
|
67
|
+
allowed_keys = [:size]
|
68
|
+
wrong_keys = array_spec.keys - allowed_keys
|
72
69
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
end
|
70
|
+
if wrong_keys.any?
|
71
|
+
errors[key] = "Not supported specification for array: #{wrong_keys.sort.join(", ")}."
|
72
|
+
end
|
73
|
+
end
|
78
74
|
end
|
79
75
|
|
80
|
-
HashValidator.
|
76
|
+
HashValidator.add_validator(HashValidator::Validator::ArrayValidator.new)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::Base
|
2
4
|
attr_accessor :name
|
3
5
|
|
@@ -6,7 +8,7 @@ class HashValidator::Validator::Base
|
|
6
8
|
self.name = name.to_s
|
7
9
|
|
8
10
|
unless self.name.size > 0
|
9
|
-
raise StandardError.new(
|
11
|
+
raise StandardError.new("Validator must be initialized with a valid name (length greater than zero)")
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
@@ -14,11 +16,36 @@ class HashValidator::Validator::Base
|
|
14
16
|
self.name == name.to_s
|
15
17
|
end
|
16
18
|
|
17
|
-
def
|
19
|
+
def error_message
|
18
20
|
"#{self.name} required"
|
19
21
|
end
|
20
22
|
|
21
|
-
def validate(
|
22
|
-
|
23
|
+
def validate(key, value, validations, errors)
|
24
|
+
# If the subclass implements valid?, use that for simple boolean validation
|
25
|
+
if self.class.instance_methods(false).include?(:valid?)
|
26
|
+
# Check the arity of the valid? method to determine how many arguments to pass
|
27
|
+
valid_result = case method(:valid?).arity
|
28
|
+
when 1
|
29
|
+
valid?(value)
|
30
|
+
when 2
|
31
|
+
valid?(value, validations)
|
32
|
+
else
|
33
|
+
raise StandardError.new("valid? method must accept either 1 argument (value) or 2 arguments (value, validations)")
|
34
|
+
end
|
35
|
+
|
36
|
+
unless valid_result
|
37
|
+
errors[key] = error_message
|
38
|
+
end
|
39
|
+
else
|
40
|
+
# Otherwise, subclass must override validate
|
41
|
+
raise StandardError.new("Validator must implement either valid? or override validate method")
|
42
|
+
end
|
23
43
|
end
|
44
|
+
|
45
|
+
# Subclasses can optionally implement this for simple boolean validation
|
46
|
+
# Return true if valid, false if invalid
|
47
|
+
# Either:
|
48
|
+
# def valid?(value) # For simple validations
|
49
|
+
# def valid?(value, validations) # When validation context is needed
|
50
|
+
# end
|
24
51
|
end
|
@@ -1,13 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::BooleanValidator < HashValidator::Validator::Base
|
2
4
|
def initialize
|
3
|
-
super(
|
5
|
+
super("boolean") # The name of the validator
|
4
6
|
end
|
5
7
|
|
6
|
-
def
|
7
|
-
|
8
|
-
errors[key] = presence_error_message
|
9
|
-
end
|
8
|
+
def valid?(value)
|
9
|
+
[TrueClass, FalseClass].include?(value.class)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
HashValidator.
|
13
|
+
HashValidator.add_validator(HashValidator::Validator::BooleanValidator.new)
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::ClassValidator < HashValidator::Validator::Base
|
2
4
|
def initialize
|
3
|
-
super(
|
5
|
+
super("_class") # 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)
|
@@ -14,4 +16,4 @@ class HashValidator::Validator::ClassValidator < HashValidator::Validator::Base
|
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
17
|
-
HashValidator.
|
19
|
+
HashValidator.add_validator(HashValidator::Validator::ClassValidator.new)
|
@@ -1,23 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::DigitsValidator < HashValidator::Validator::Base
|
2
4
|
def initialize
|
3
|
-
super(
|
4
|
-
end
|
5
|
-
|
6
|
-
def presence_error_message
|
7
|
-
'must contain only digits'
|
5
|
+
super("digits") # The name of the validator
|
8
6
|
end
|
9
7
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
8
|
+
def error_message
|
9
|
+
"must contain only digits"
|
14
10
|
end
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
def valid_digits?(value)
|
19
|
-
/\A\d+\z/.match?(value)
|
12
|
+
def valid?(value)
|
13
|
+
value.is_a?(String) && /\A\d+\z/.match?(value)
|
20
14
|
end
|
21
15
|
end
|
22
16
|
|
23
|
-
HashValidator.
|
17
|
+
HashValidator.add_validator(HashValidator::Validator::DigitsValidator.new)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class HashValidator::Validator::DynamicFuncValidator < HashValidator::Validator::Base
|
4
|
+
attr_accessor :func, :custom_error_message
|
5
|
+
|
6
|
+
def initialize(name, func, error_message = nil)
|
7
|
+
super(name)
|
8
|
+
|
9
|
+
unless func.respond_to?(:call)
|
10
|
+
raise ArgumentError, "Function must be callable (proc or lambda)"
|
11
|
+
end
|
12
|
+
|
13
|
+
@func = func
|
14
|
+
@custom_error_message = error_message
|
15
|
+
end
|
16
|
+
|
17
|
+
def error_message
|
18
|
+
@custom_error_message || super
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?(value)
|
22
|
+
!!@func.call(value)
|
23
|
+
rescue
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class HashValidator::Validator::DynamicPatternValidator < HashValidator::Validator::Base
|
4
|
+
attr_accessor :pattern, :custom_error_message
|
5
|
+
|
6
|
+
def initialize(name, pattern, error_message = nil)
|
7
|
+
super(name)
|
8
|
+
|
9
|
+
unless pattern.is_a?(Regexp)
|
10
|
+
raise ArgumentError, "Pattern must be a regular expression"
|
11
|
+
end
|
12
|
+
|
13
|
+
@pattern = pattern
|
14
|
+
@custom_error_message = error_message
|
15
|
+
end
|
16
|
+
|
17
|
+
def error_message
|
18
|
+
@custom_error_message || super
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?(value)
|
22
|
+
return false unless value.respond_to?(:to_s)
|
23
|
+
@pattern.match?(value.to_s)
|
24
|
+
end
|
25
|
+
end
|
@@ -1,17 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::EmailValidator < HashValidator::Validator::Base
|
2
4
|
def initialize
|
3
|
-
super(
|
5
|
+
super("email") # The name of the validator
|
4
6
|
end
|
5
7
|
|
6
|
-
def
|
7
|
-
|
8
|
+
def error_message
|
9
|
+
"is not a valid email"
|
8
10
|
end
|
9
11
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
12
|
+
def valid?(value)
|
13
|
+
value.is_a?(String) && value.include?("@")
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
HashValidator.
|
17
|
+
HashValidator.add_validator(HashValidator::Validator::EmailValidator.new)
|
@@ -1,21 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::EnumerableValidator < HashValidator::Validator::Base
|
2
4
|
def initialize
|
3
|
-
super(
|
5
|
+
super("_enumerable") # 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?(Enumerable)
|
8
10
|
end
|
9
11
|
|
10
|
-
def
|
11
|
-
|
12
|
+
def error_message
|
13
|
+
"value from list required"
|
12
14
|
end
|
13
15
|
|
14
|
-
def
|
15
|
-
|
16
|
-
errors[key] = presence_error_message
|
17
|
-
end
|
16
|
+
def valid?(value, validations)
|
17
|
+
validations.include?(value)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
HashValidator.
|
21
|
+
HashValidator.add_validator(HashValidator::Validator::EnumerableValidator.new)
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::HashValidator < HashValidator::Validator::Base
|
2
4
|
def initialize
|
3
|
-
super(
|
5
|
+
super("hash")
|
4
6
|
end
|
5
7
|
|
6
8
|
def should_validate?(rhs)
|
@@ -15,7 +17,7 @@ class HashValidator::Validator::HashValidator < HashValidator::Validator::Base
|
|
15
17
|
|
16
18
|
# Validate hash
|
17
19
|
unless value.is_a?(Hash)
|
18
|
-
errors[key] =
|
20
|
+
errors[key] = error_message
|
19
21
|
return
|
20
22
|
end
|
21
23
|
|
@@ -28,14 +30,14 @@ class HashValidator::Validator::HashValidator < HashValidator::Validator::Base
|
|
28
30
|
|
29
31
|
if HashValidator::Base.strict?
|
30
32
|
value.keys.each do |k|
|
31
|
-
errors[k] =
|
33
|
+
errors[k] = "key not expected" unless validations[k]
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
37
|
# Cleanup errors (remove any empty nested errors)
|
36
|
-
errors.delete_if { |_,v| v.empty? }
|
38
|
+
errors.delete_if { |_, v| v.empty? }
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
40
42
|
|
41
|
-
HashValidator.
|
43
|
+
HashValidator.add_validator(HashValidator::Validator::HashValidator.new)
|
@@ -1,23 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class HashValidator::Validator::HexColorValidator < HashValidator::Validator::Base
|
2
4
|
def initialize
|
3
|
-
super(
|
4
|
-
end
|
5
|
-
|
6
|
-
def presence_error_message
|
7
|
-
'is not a valid hex color'
|
5
|
+
super("hex_color") # The name of the validator
|
8
6
|
end
|
9
7
|
|
10
|
-
def
|
11
|
-
|
12
|
-
errors[key] = presence_error_message
|
13
|
-
end
|
8
|
+
def error_message
|
9
|
+
"is not a valid hex color"
|
14
10
|
end
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
def valid_hex_color?(value)
|
19
|
-
/\A#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/.match?(value)
|
12
|
+
def valid?(value)
|
13
|
+
value.is_a?(String) && /\A#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/.match?(value)
|
20
14
|
end
|
21
15
|
end
|
22
16
|
|
23
|
-
HashValidator.
|
17
|
+
HashValidator.add_validator(HashValidator::Validator::HexColorValidator.new)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ipaddr"
|
4
|
+
|
5
|
+
class HashValidator::Validator::IpValidator < HashValidator::Validator::Base
|
6
|
+
def initialize
|
7
|
+
super("ip") # The name of the validator
|
8
|
+
end
|
9
|
+
|
10
|
+
def error_message
|
11
|
+
"is not a valid IP address"
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?(value)
|
15
|
+
return false unless value.is_a?(String)
|
16
|
+
# Use IPAddr to validate both IPv4 and IPv6 addresses
|
17
|
+
IPAddr.new(value)
|
18
|
+
true
|
19
|
+
rescue IPAddr::Error, IPAddr::InvalidAddressError
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
HashValidator.add_validator(HashValidator::Validator::IpValidator.new)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class HashValidator::Validator::Ipv4Validator < HashValidator::Validator::Base
|
4
|
+
def initialize
|
5
|
+
super("ipv4") # The name of the validator
|
6
|
+
end
|
7
|
+
|
8
|
+
def error_message
|
9
|
+
"is not a valid IPv4 address"
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(value)
|
13
|
+
return false unless value.is_a?(String)
|
14
|
+
# IPv4 regex: 4 octets, each 0-255
|
15
|
+
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/
|
16
|
+
value.match?(ipv4_regex)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
HashValidator.add_validator(HashValidator::Validator::Ipv4Validator.new)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ipaddr"
|
4
|
+
|
5
|
+
class HashValidator::Validator::Ipv6Validator < HashValidator::Validator::Base
|
6
|
+
def initialize
|
7
|
+
super("ipv6") # The name of the validator
|
8
|
+
end
|
9
|
+
|
10
|
+
def error_message
|
11
|
+
"is not a valid IPv6 address"
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?(value)
|
15
|
+
return false unless value.is_a?(String)
|
16
|
+
# Use IPAddr to validate IPv6 addresses (handles standard and compressed notation)
|
17
|
+
addr = IPAddr.new(value)
|
18
|
+
addr.ipv6?
|
19
|
+
rescue IPAddr::Error, IPAddr::InvalidAddressError
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
HashValidator.add_validator(HashValidator::Validator::Ipv6Validator.new)
|
@@ -1,23 +1,18 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
2
4
|
|
3
5
|
class HashValidator::Validator::JsonValidator < HashValidator::Validator::Base
|
4
6
|
def initialize
|
5
|
-
super(
|
6
|
-
end
|
7
|
-
|
8
|
-
def presence_error_message
|
9
|
-
'is not valid JSON'
|
7
|
+
super("json") # 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 valid JSON"
|
16
12
|
end
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
def valid_json?(value)
|
14
|
+
def valid?(value)
|
15
|
+
return false unless value.is_a?(String)
|
21
16
|
JSON.parse(value)
|
22
17
|
true
|
23
18
|
rescue JSON::ParserError
|
@@ -25,4 +20,4 @@ class HashValidator::Validator::JsonValidator < HashValidator::Validator::Base
|
|
25
20
|
end
|
26
21
|
end
|
27
22
|
|
28
|
-
HashValidator.
|
23
|
+
HashValidator.add_validator(HashValidator::Validator::JsonValidator.new)
|