kharon 1.1.0 → 1.1.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 +5 -13
- data/{.rspec → .rspec.old} +0 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +12 -4
- data/dist/kharon-1.1.0.gem +0 -0
- data/doc/Kharon.html +384 -6
- data/doc/Kharon/Errors.html +1 -1
- data/doc/Kharon/Errors/Validation.html +1 -1
- data/doc/Kharon/Handlers.html +1 -1
- data/doc/Kharon/Handlers/Exceptions.html +1 -1
- data/doc/Kharon/Handlers/Messages.html +1 -1
- data/doc/Kharon/Processor.html +425 -0
- data/doc/Kharon/Processors.html +144 -0
- data/doc/Kharon/Processors/ArrayProcessor.html +429 -0
- data/doc/Kharon/Processors/BooleanProcessor.html +306 -0
- data/doc/Kharon/Processors/BoxProcessor.html +440 -0
- data/doc/Kharon/Processors/DateProcessor.html +306 -0
- data/doc/Kharon/Processors/DatetimeProcessor.html +306 -0
- data/doc/Kharon/Processors/EmailProcessor.html +307 -0
- data/doc/Kharon/Processors/HashProcessor.html +431 -0
- data/doc/Kharon/Processors/IntegerProcessor.html +441 -0
- data/doc/Kharon/Processors/NumericProcessor.html +463 -0
- data/doc/Kharon/Processors/SSIDProcessor.html +307 -0
- data/doc/Kharon/Processors/TextProcessor.html +430 -0
- data/doc/Kharon/Validate.html +17 -5
- data/doc/Kharon/Validator.html +198 -1194
- data/doc/_index.html +159 -1
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +15 -4
- data/doc/index.html +15 -4
- data/doc/method_list.html +135 -39
- data/doc/top-level-namespace.html +1 -1
- data/kharon.gemspec +4 -2
- data/lib/kharon.rb +32 -2
- data/lib/kharon/processor.rb +162 -0
- data/lib/kharon/processors.rb +6 -0
- data/lib/kharon/processors/array_processor.rb +30 -0
- data/lib/kharon/processors/boolean_processor.rb +31 -0
- data/lib/kharon/processors/box_processor.rb +63 -0
- data/lib/kharon/processors/date_processor.rb +21 -0
- data/lib/kharon/processors/datetime_processor.rb +21 -0
- data/lib/kharon/processors/email_processor.rb +21 -0
- data/lib/kharon/processors/hash_processor.rb +31 -0
- data/lib/kharon/processors/integer_processor.rb +55 -0
- data/lib/kharon/processors/numeric_processor.rb +66 -0
- data/lib/kharon/processors/ssid_processor.rb +21 -0
- data/lib/kharon/processors/text_processor.rb +30 -0
- data/lib/kharon/validate.rb +1 -1
- data/lib/kharon/validator.rb +26 -390
- data/lib/kharon/version.rb +1 -1
- data/spec/results.html +5277 -321
- metadata +69 -28
@@ -0,0 +1,31 @@
|
|
1
|
+
module Kharon
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
# Processor to validate hashes. It has the :has_keys and :contains options with the default ones.
|
5
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
6
|
+
class HashProcessor < Kharon::Processor
|
7
|
+
|
8
|
+
Kharon.add_processor(:hash, Kharon::Processors::HashProcessor)
|
9
|
+
|
10
|
+
# Checks if the given key is a datetime or not.
|
11
|
+
# @param [Object] key the key about which verify the type.
|
12
|
+
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
13
|
+
# @example Validates a key so it has to be a datetime, and depends on two other keys.
|
14
|
+
# @validator.datetime(:a_datetime, dependencies: [:another_key, :a_third_key])
|
15
|
+
def process(key, options = {})
|
16
|
+
before_all(key, options)
|
17
|
+
is_typed?(key, Hash) ? store(key, ->(item){Hash.try_convert(item)}, options) : raise_type_error(key, "Hash")
|
18
|
+
end
|
19
|
+
|
20
|
+
# Stores an array after verifying that it contains the values given in the contains? option.
|
21
|
+
# @param [Object] key the key associated with the value to store in the filtered datas.
|
22
|
+
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
23
|
+
# @param [Hash] options the options applied to the initial value.
|
24
|
+
def store(key, process, options)
|
25
|
+
has_keys?(key, options[:has_keys]) if(options.has_key?(:has_keys))
|
26
|
+
contains?(validator.filtered, validator.datas[key].values, options[:contains]) if(options.has_key?(:contains))
|
27
|
+
super(key, process, options)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Kharon
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
# Processor to validate integers. It has the :between, :min, and :max options with the default ones.
|
5
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
6
|
+
class IntegerProcessor < Kharon::Processor
|
7
|
+
|
8
|
+
Kharon.add_processor(:integer, Kharon::Processors::IntegerProcessor)
|
9
|
+
|
10
|
+
# Checks if the given key is an integer or not.
|
11
|
+
# @param [Object] key the key about which verify the type.
|
12
|
+
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
13
|
+
# @example Validates a key so it has to be an integer superior or equal to 2.
|
14
|
+
# @validator.integer(:an_integer_key, min: 2)
|
15
|
+
def process(key, options = {})
|
16
|
+
before_all(key, options)
|
17
|
+
match?(key, /\A\d+\Z/) ? store(key, ->(item){item.to_i}, options) : raise_type_error(key, "Integer")
|
18
|
+
end
|
19
|
+
|
20
|
+
# Stores a numeric number after checking its limits if given.
|
21
|
+
# @param [Object] key the key associated with the value to store in the filtered datas.
|
22
|
+
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
23
|
+
# @param [Hash] options the options applied to the initial value.
|
24
|
+
def store(key, process, options = {})
|
25
|
+
if(options.has_key?(:between))
|
26
|
+
check_min_value(key, options[:between][0])
|
27
|
+
check_max_value(key, options[:between][1])
|
28
|
+
else
|
29
|
+
check_min_value(key, options[:min]) if(options.has_key?(:min))
|
30
|
+
check_max_value(key, options[:max]) if(options.has_key?(:max))
|
31
|
+
end
|
32
|
+
super(key, process, options)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Checks if the value associated with the given key is greater than the given minimum value.
|
38
|
+
# @param [Object] key the key associated with the value to compare.
|
39
|
+
# @param [Numeric] min_value the required minimum value.
|
40
|
+
# @raise [ArgumentError] if the initial value is strictly lesser than the minimum value.
|
41
|
+
def check_min_value(key, min_value)
|
42
|
+
raise_error(type: "min", supposed: min_value, key: key, value: validator.datas[key]) unless validator.datas[key].to_i >= min_value.to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
# Checks if the value associated with the given key is lesser than the given maximum value.
|
46
|
+
# @param [Object] key the key associated with the value to compare.
|
47
|
+
# @param [Numeric] max_value the required maximum value.
|
48
|
+
# @raise [ArgumentError] if the initial value is strictly greater than the minimum value.
|
49
|
+
def check_max_value(key, max_value)
|
50
|
+
raise_error(type: "max", supposed: max_value, key: key, value: validator.datas[key]) unless validator.datas[key].to_i <= max_value.to_i
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Kharon
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
# Processor to validate integers. It has the :between, :round, :floor, :ceil, :min, and :max options with the default ones.
|
5
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
6
|
+
class NumericProcessor < Kharon::Processor
|
7
|
+
|
8
|
+
Kharon.add_processor(:numeric, Kharon::Processors::NumericProcessor)
|
9
|
+
|
10
|
+
# Checks if the given key is an integer or not.
|
11
|
+
# @param [Object] key the key about which verify the type.
|
12
|
+
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
13
|
+
# @example Validates a key so it has to be an integer superior or equal to 2.
|
14
|
+
# @validator.integer(:an_integer_key, min: 2)
|
15
|
+
def process(key, options = {})
|
16
|
+
before_all(key, options)
|
17
|
+
match?(key, /\A([+-]?\d+)([,.](\d+))?\Z/) ? store(key, ->(item){item.to_s.sub(/,/, ".").to_f}, options) : raise_type_error(key, "Numeric")
|
18
|
+
end
|
19
|
+
|
20
|
+
# Stores a decimal number, then apply the eventually passed round, ceil, or floor options.
|
21
|
+
# @param [Object] key the key associated with the value to store in the filtered datas.
|
22
|
+
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
23
|
+
# @param [Hash] options the options applied to the initial value.
|
24
|
+
def store(key, process, options)
|
25
|
+
if(options.has_key?(:between))
|
26
|
+
check_min_value(key, options[:between][0])
|
27
|
+
check_max_value(key, options[:between][1])
|
28
|
+
else
|
29
|
+
check_min_value(key, options[:min]) if(options.has_key?(:min))
|
30
|
+
check_max_value(key, options[:max]) if(options.has_key?(:max))
|
31
|
+
end
|
32
|
+
super(key, process, options)
|
33
|
+
if options.has_key?(:round)
|
34
|
+
if options[:round].kind_of?(Integer)
|
35
|
+
validator.filtered[key] = validator.filtered[key].round(options[:round]) if validator.filtered.has_key?(key)
|
36
|
+
elsif options[:round] == true
|
37
|
+
validator.filtered[key] = validator.filtered[key].round if validator.filtered.has_key?(key)
|
38
|
+
end
|
39
|
+
elsif(options.has_key?(:floor) and options[:floor] == true)
|
40
|
+
validator.filtered[key] = validator.filtered[key].floor if validator.filtered.has_key?(key)
|
41
|
+
elsif(options.has_key?(:ceil) and options[:ceil] == true)
|
42
|
+
validator.filtered[key] = validator.filtered[key].ceil if validator.filtered.has_key?(key)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Checks if the value associated with the given key is greater than the given minimum value.
|
49
|
+
# @param [Object] key the key associated with the value to compare.
|
50
|
+
# @param [Numeric] min_value the required minimum value.
|
51
|
+
# @raise [ArgumentError] if the initial value is strictly lesser than the minimum value.
|
52
|
+
def check_min_value(key, min_value)
|
53
|
+
raise_error(type: "min", supposed: min_value, key: key, value: validator.datas[key]) unless validator.datas[key].to_i >= min_value.to_i
|
54
|
+
end
|
55
|
+
|
56
|
+
# Checks if the value associated with the given key is lesser than the given maximum value.
|
57
|
+
# @param [Object] key the key associated with the value to compare.
|
58
|
+
# @param [Numeric] max_value the required maximum value.
|
59
|
+
# @raise [ArgumentError] if the initial value is strictly greater than the minimum value.
|
60
|
+
def check_max_value(key, max_value)
|
61
|
+
raise_error(type: "max", supposed: max_value, key: key, value: validator.datas[key]) unless validator.datas[key].to_i <= max_value.to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Kharon
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
# Processor to validate MongoDB SSID. It only has the default options.
|
5
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
6
|
+
class SSIDProcessor < Kharon::Processor
|
7
|
+
|
8
|
+
Kharon.add_processor(:ssid, Kharon::Processors::SSIDProcessor)
|
9
|
+
|
10
|
+
# Checks if the given key is a not-empty string or not.
|
11
|
+
# @param [Object] key the key about which verify the type.
|
12
|
+
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
13
|
+
# @example Validates a key so it has to be a string, and seems like and email address (not sure of the regular expression though).
|
14
|
+
# @validator.text(:an_email, regex: "[a-zA-Z]+@[a-zA-Z]+\.[a-zA-Z]{2-4}")
|
15
|
+
def process(key, options = {})
|
16
|
+
before_all(key, options)
|
17
|
+
match?(key, /^[0-9a-fA-F]{24}$/) ? store(key, ->(item){BSON::ObjectId.from_string(item.to_s)}, options) : raise_type_error(key, "Moped::BSON::ObjectId")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Kharon
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
# Processor to validate simple strings. It has the :regex option plus the default ones.
|
5
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
6
|
+
class TextProcessor < Kharon::Processor
|
7
|
+
|
8
|
+
Kharon.add_processor(:text, Kharon::Processors::TextProcessor)
|
9
|
+
|
10
|
+
# Checks if the given key is a not-empty string or not.
|
11
|
+
# @param [Object] key the key about which verify the type.
|
12
|
+
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
13
|
+
# @example Validates a key so it has to be a string, and seems like and email address (not sure of the regular expression though).
|
14
|
+
# @validator.text(:an_email, regex: "[a-zA-Z]+@[a-zA-Z]+\.[a-zA-Z]{2-4}")
|
15
|
+
def process(key, options = {})
|
16
|
+
before_all(key, options)
|
17
|
+
is_typed?(key, String) ? store(key, ->(item){item.to_s}, options) : raise_type_error(key, "String")
|
18
|
+
end
|
19
|
+
|
20
|
+
# Stores a string after verifying that it respects a regular expression given in parameter.
|
21
|
+
# @param [Object] key the key associated with the value to store in the filtered datas.
|
22
|
+
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
23
|
+
# @param [Hash] options the options applied to the initial value.
|
24
|
+
def store(key, process, options)
|
25
|
+
match_regex?(key, validator.datas[key], options[:regex]) if(options.has_key?(:regex))
|
26
|
+
super(key, process, options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/kharon/validate.rb
CHANGED
@@ -14,7 +14,7 @@ module Kharon
|
|
14
14
|
rescue Kharon::Errors::Validation => exception
|
15
15
|
raise exception
|
16
16
|
rescue Exception => exception
|
17
|
-
raise Kharon::Errors::Validation.new({type: "standard", exception: exception.class.to_s,
|
17
|
+
raise Kharon::Errors::Validation.new({type: "standard", exception: exception.class.to_s, message: exception.message, backtrace: exception.backtrace})
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
data/lib/kharon/validator.rb
CHANGED
@@ -8,6 +8,10 @@ module Kharon
|
|
8
8
|
# @return [Hash] The datas to filter, they shouldn't be modified to guarantee their integrity.
|
9
9
|
attr_reader :datas
|
10
10
|
|
11
|
+
# @!attribute [r] processors
|
12
|
+
# @return [Hash] THe processors to process and validate the keys depending on their types.
|
13
|
+
attr_reader :processors
|
14
|
+
|
11
15
|
# @!attribute [rw] filtered
|
12
16
|
# @return [Hash] The filtered datas are the datas after they have been filtered (renamed keys for example) by the validator.
|
13
17
|
attr_accessor :filtered
|
@@ -21,408 +25,40 @@ module Kharon
|
|
21
25
|
# @example create a new instance of validator.
|
22
26
|
# @validator = Kharon::Validator.new({key: "value"})
|
23
27
|
def initialize(datas)
|
24
|
-
@datas
|
25
|
-
@
|
26
|
-
@
|
27
|
-
|
28
|
-
|
29
|
-
# Checks if the given key is an integer or not.
|
30
|
-
# @param [Object] key the key about which verify the type.
|
31
|
-
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
32
|
-
# @example Validates a key so it has to be an integer superior or equal to 2.
|
33
|
-
# @validator.integer(:an_integer_key, min: 2)
|
34
|
-
def integer(key, options = {})
|
35
|
-
before_all(key, options)
|
36
|
-
match?(key, /\A\d+\Z/) ? store_numeric(key, ->(item){item.to_i}, options) : raise_type_error(key, "Integer")
|
37
|
-
end
|
38
|
-
|
39
|
-
# Checks if the given key is a numeric or not.
|
40
|
-
# @param [Object] key the key about which verify the type.
|
41
|
-
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
42
|
-
# @example Validates a key so it has to be a numeric, is required and is between 2 and 5.5.
|
43
|
-
# @validator.numeric(:a_numeric_key, required: true, between: [2, 5.5])
|
44
|
-
def numeric(key, options = {})
|
45
|
-
before_all(key, options)
|
46
|
-
match?(key, /\A([+-]?\d+)([,.](\d+))?\Z/) ? store_decimal(key, ->(item){item.to_s.sub(/,/, ".").to_f}, options) : raise_type_error(key, "Numeric")
|
47
|
-
end
|
48
|
-
|
49
|
-
# Checks if the given key is a not-empty string or not.
|
50
|
-
# @param [Object] key the key about which verify the type.
|
51
|
-
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
52
|
-
# @example Validates a key so it has to be a string, and seems like and email address (not sure of the regular expression though).
|
53
|
-
# @validator.text(:an_email, regex: "[a-zA-Z]+@[a-zA-Z]+\.[a-zA-Z]{2-4}")
|
54
|
-
def text(key, options = {})
|
55
|
-
before_all(key, options)
|
56
|
-
is_typed?(key, String) ? store_text(key, ->(item){item.to_s}, options) : raise_type_error(key, "String")
|
57
|
-
end
|
58
|
-
|
59
|
-
# Doesn't check the type of the key and let it pass without modification.
|
60
|
-
# @param [Object] key the key about which verify the type.
|
61
|
-
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
62
|
-
# @example Just checks if the key is in the hash.
|
63
|
-
# @validator.any(:a_key, required: true)
|
64
|
-
def any(key, options = {})
|
65
|
-
before_all(key, options)
|
66
|
-
store(key, ->(item){item}, options)
|
67
|
-
end
|
68
|
-
|
69
|
-
# Checks if the given key is a datetime or not.
|
70
|
-
# @param [Object] key the key about which verify the type.
|
71
|
-
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
72
|
-
# @example Validates a key so it has to be a datetime, and depends on two other keys.
|
73
|
-
# @validator.datetime(:a_datetime, dependencies: [:another_key, :a_third_key])
|
74
|
-
def datetime(key, options = {})
|
75
|
-
before_all(key, options)
|
76
|
-
begin; store(key, ->(item){DateTime.parse(item.to_s)} , options); rescue; raise_type_error(key, "DateTime"); end
|
28
|
+
@datas = Hash[datas.map { |k, v| [k.to_sym, v] }]
|
29
|
+
@processors = Hash[Kharon.processors.map { |name, classname| [name, classname.new(self)] }]
|
30
|
+
@filtered = Hash.new
|
31
|
+
@handler = Kharon.errors_handler
|
77
32
|
end
|
78
33
|
|
79
|
-
#
|
80
|
-
# @param [
|
81
|
-
# @param [
|
82
|
-
# @
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
34
|
+
# Method used to not directly define the different type validation methods, but instead to look for it in the processors list.
|
35
|
+
# @param [String] name the name of the not found method.
|
36
|
+
# @param [Array] arguments the arguments passed to the not found method when it's called.
|
37
|
+
# @param [Proc] block the block that might have been passed to the not found method when it's called.
|
38
|
+
def method_missing(name, *arguments, &block)
|
39
|
+
if respond_to? name
|
40
|
+
if arguments.count == 1
|
41
|
+
processors[name].process(arguments[0])
|
42
|
+
elsif arguments.count == 2
|
43
|
+
processors[name].process(arguments[0], arguments[1])
|
44
|
+
end
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
87
48
|
end
|
88
49
|
|
89
|
-
|
90
|
-
|
91
|
-
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
92
|
-
# @example Validates a key so it has to be an array, and checks if it has some values in it.
|
93
|
-
# @validator.date(:an_array, contains?: ["first", "second"])
|
94
|
-
def array(key, options = {})
|
95
|
-
before_all(key, options)
|
96
|
-
is_typed?(key, Array) ? store_array(key, ->(item){item.to_a}, options) : raise_type_error(key, "Array")
|
50
|
+
def respond_to?(name, search_private = false)
|
51
|
+
processors.keys.include?(name) ? true : super
|
97
52
|
end
|
98
53
|
|
99
54
|
# Checks if the given key is a hash or not.
|
55
|
+
# This method MUST be defined to override the #hash method with these parameters.
|
100
56
|
# @param [Object] key the key about which verify the type.
|
101
57
|
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
102
58
|
# @example Validates a key so it has to be a hash, and checks if it has some keys.
|
103
59
|
# @validator.date(:a_hash, has_keys: [:first, :second])
|
104
60
|
def hash(key, options = {})
|
105
|
-
|
106
|
-
is_typed?(key, Hash) ? store_hash(key, ->(item){Hash.try_convert(item)}, options) : raise_type_error(key, "Hash")
|
107
|
-
end
|
108
|
-
|
109
|
-
# Checks if the given key is a boolean or not.
|
110
|
-
# @param [Object] key the key about which verify the type.
|
111
|
-
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
112
|
-
# @example Validates a key so it has to be a boolean.
|
113
|
-
# @validator.boolean(:a_boolean)
|
114
|
-
def boolean(key, options = {})
|
115
|
-
before_all(key, options)
|
116
|
-
match?(key, /(true)|(false)/) ? store(key, ->(item){to_boolean(item)}, options) : raise_type_error(key, "Numeric")
|
117
|
-
end
|
118
|
-
|
119
|
-
# Checks if the given key is a SSID for a MongoDB object or not.
|
120
|
-
# @param [Object] key the key about which verify the type.
|
121
|
-
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
122
|
-
# @example Validates a key so it has to be a MongoDB SSID.
|
123
|
-
# @validator.ssid(:a_ssid)
|
124
|
-
def ssid(key, options = {})
|
125
|
-
before_all(key, options)
|
126
|
-
match?(key, /^[0-9a-fA-F]{24}$/) ? store(key, ->(item){BSON::ObjectId.from_string(item.to_s)}, options) : raise_type_error(key, "Moped::BSON::ObjectId")
|
127
|
-
end
|
128
|
-
|
129
|
-
# Checks if the given key is a box (geofences) or not. A box is composed of four numbers (positive or negative, decimal or not) separed by commas.
|
130
|
-
# @param [Object] key the key about which verify the type.
|
131
|
-
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
132
|
-
# @example Validates a key so it has to be a box.
|
133
|
-
# @validator.box(:a_box)
|
134
|
-
def box(key, options = {})
|
135
|
-
before_all(key, options)
|
136
|
-
match?(key, /^(?:[+-]?\d{1,3}(?:\.\d{1,7})?,?){4}$/) ? store_box(key, options) : raise_type_error(key, "Box")
|
137
|
-
end
|
138
|
-
|
139
|
-
# Checks if the given key is an email or not.
|
140
|
-
# @param [Object] key the key about which verify the type.
|
141
|
-
# @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
|
142
|
-
# @example Validates a key so it has to be an email.
|
143
|
-
# @validator.email(:email)
|
144
|
-
def email(key, options = {})
|
145
|
-
before_all(key, options)
|
146
|
-
match?(key, /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/) ? store(key, ->(item){item}, options) : raise_type_error(key, "Email")
|
147
|
-
end
|
148
|
-
|
149
|
-
def method_missing(name, *arguments, &block)
|
150
|
-
respond_to?(name) ? datas[name] : super
|
151
|
-
end
|
152
|
-
|
153
|
-
def respond_to?(name, include_private = false)
|
154
|
-
datas.keys.include?(name.to_sym) ? true : super
|
155
|
-
end
|
156
|
-
|
157
|
-
private
|
158
|
-
|
159
|
-
# This method is executed before any call to a public method.
|
160
|
-
# @param [Object] key the key associated with the value currently filteres in the filtered datas.
|
161
|
-
# @param [Hash] options the options applied to the initial value.
|
162
|
-
def before_all(key, options)
|
163
|
-
required(key) if (options.has_key?(:required) and options[:required] == true)
|
164
|
-
if options.has_key?(:dependencies)
|
165
|
-
dependencies(key, options[:dependencies])
|
166
|
-
elsif options.has_key?(:dependency)
|
167
|
-
dependency(key, options[:dependency])
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
# Stores a numeric number after checking its limits if given.
|
172
|
-
# @param [Object] key the key associated with the value to store in the filtered datas.
|
173
|
-
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
174
|
-
# @param [Hash] options the options applied to the initial value.
|
175
|
-
def store_numeric(key, process, options)
|
176
|
-
if(options.has_key?(:between))
|
177
|
-
check_min_value(key, options[:between][0])
|
178
|
-
check_max_value(key, options[:between][1])
|
179
|
-
else
|
180
|
-
check_min_value(key, options[:min]) if(options.has_key?(:min))
|
181
|
-
check_max_value(key, options[:max]) if(options.has_key?(:max))
|
182
|
-
end
|
183
|
-
store(key, process, options)
|
184
|
-
end
|
185
|
-
|
186
|
-
# Stores a decimal number, then apply the eventually passed round, ceil, or floor options.
|
187
|
-
# @param [Object] key the key associated with the value to store in the filtered datas.
|
188
|
-
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
189
|
-
# @param [Hash] options the options applied to the initial value.
|
190
|
-
def store_decimal(key, process, options)
|
191
|
-
store_numeric(key, process, options)
|
192
|
-
if options.has_key?(:round)
|
193
|
-
store_rounded_decimal(key, process, options)
|
194
|
-
elsif(options.has_key?(:floor) and options[:floor] == true)
|
195
|
-
filtered[key] = filtered[key].floor if filtered.has_key?(key)
|
196
|
-
elsif(options.has_key?(:ceil) and options[:ceil] == true)
|
197
|
-
filtered[key] = filtered[key].ceil if filtered.has_key?(key)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
# Stores a decimal after rounding it with the convenient number of decimals.
|
202
|
-
# @param [Object] key the key associated with the value to store in the filtered datas.
|
203
|
-
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
204
|
-
# @param [Hash] options the options applied to the initial value.
|
205
|
-
def store_rounded_decimal(key, process, options)
|
206
|
-
if options[:round].kind_of?(Integer)
|
207
|
-
filtered[key] = filtered[key].round(options[:round]) if filtered.has_key?(key)
|
208
|
-
elsif options[:round] == true
|
209
|
-
filtered[key] = filtered[key].round if filtered.has_key?(key)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
# Stores a hash after checking for the contains? and has_keys options.
|
214
|
-
# @param [Object] key the key associated with the value to store in the filtered datas.
|
215
|
-
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
216
|
-
# @param [Hash] options the options applied to the initial value.
|
217
|
-
def store_hash(key, process, options)
|
218
|
-
has_keys?(key, options[:has_keys]) if(options.has_key?(:has_keys))
|
219
|
-
contains?(filtered, datas[key].values, options[:contains]) if(options.has_key?(:contains))
|
220
|
-
store(key, process, options)
|
221
|
-
end
|
222
|
-
|
223
|
-
# Stores an array after verifying that it contains the values given in the contains? option.
|
224
|
-
# @param [Object] key the key associated with the value to store in the filtered datas.
|
225
|
-
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
226
|
-
# @param [Hash] options the options applied to the initial value.
|
227
|
-
def store_array(key, process, options)
|
228
|
-
contains?(key, datas[key], options[:contains]) if(options.has_key?(:contains))
|
229
|
-
store(key, process, options)
|
230
|
-
end
|
231
|
-
|
232
|
-
# Stores a string after verifying that it respects a regular expression given in parameter.
|
233
|
-
# @param [Object] key the key associated with the value to store in the filtered datas.
|
234
|
-
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
235
|
-
# @param [Hash] options the options applied to the initial value.
|
236
|
-
def store_text(key, process, options)
|
237
|
-
match_regex?(key, datas[key], options[:regex]) if(options.has_key?(:regex))
|
238
|
-
store(key, process, options)
|
239
|
-
end
|
240
|
-
|
241
|
-
def store_box(key, options)
|
242
|
-
if(options.has_key?(:at_least))
|
243
|
-
box_contains?(key, datas[key], options[:at_least])
|
244
|
-
end
|
245
|
-
if(options.has_key?(:at_most))
|
246
|
-
box_contains?(key, options[:at_most], datas[key])
|
247
|
-
end
|
248
|
-
store(key, ->(item){parse_box(key, datas[key])}, options)
|
249
|
-
end
|
250
|
-
|
251
|
-
# Checks if a required key is present in provided datas.
|
252
|
-
# @param [Object] key the key of which check the presence.
|
253
|
-
# @raise [ArgumentError] if the key is not present.
|
254
|
-
def required(key)
|
255
|
-
raise_error(type: "required", key: key) unless @datas.has_key?(key)
|
256
|
-
end
|
257
|
-
|
258
|
-
# Syntaxic sugar used to chack several dependencies at once.
|
259
|
-
# @param [Object] key the key needing another key to properly work.
|
260
|
-
# @param [Object] dependencies the keys needed by another key for it to properly work.
|
261
|
-
# @raise [ArgumentError] if the required dependencies are not present.
|
262
|
-
# @see self#check_dependency the associated singular method.
|
263
|
-
def dependencies(key, dependencies)
|
264
|
-
dependencies.each { |dependency| dependency(key, dependency) }
|
265
|
-
end
|
266
|
-
|
267
|
-
# Checks if a dependency is respected. A dependency is a key openly needed by another key.
|
268
|
-
# @param [Object] key the key needing another key to properly work.
|
269
|
-
# @param [Object] dependency the key needed by another key for it to properly work.
|
270
|
-
# @raise [ArgumentError] if the required dependency is not present.
|
271
|
-
def dependency(key, dependency)
|
272
|
-
raise_error(type: "dependency", key: "key", needed: dependency) unless @datas.has_key?(dependency)
|
273
|
-
end
|
274
|
-
|
275
|
-
# Checks if the value associated with the given key is greater than the given minimum value.
|
276
|
-
# @param [Object] key the key associated with the value to compare.
|
277
|
-
# @param [Numeric] min_value the required minimum value.
|
278
|
-
# @raise [ArgumentError] if the initial value is strictly lesser than the minimum value.
|
279
|
-
def check_min_value(key, min_value)
|
280
|
-
raise_error(type: "min", supposed: min_value, key: key, value: datas[key]) unless datas[key].to_i >= min_value.to_i
|
281
|
-
end
|
282
|
-
|
283
|
-
# Checks if the value associated with the given key is lesser than the given maximum value.
|
284
|
-
# @param [Object] key the key associated with the value to compare.
|
285
|
-
# @param [Numeric] max_value the required maximum value.
|
286
|
-
# @raise [ArgumentError] if the initial value is strictly greater than the minimum value.
|
287
|
-
def check_max_value(key, max_value)
|
288
|
-
raise_error(type: "max", supposed: max_value, key: key, value: datas[key]) unless datas[key].to_i <= max_value.to_i
|
289
|
-
end
|
290
|
-
|
291
|
-
# Checks if the value associated with the given key is included in the given array of values.
|
292
|
-
# @param [Object] key the key associated with the value to check.
|
293
|
-
# @param [Array] values the values in which the initial value should be contained.
|
294
|
-
# @raise [ArgumentError] if the initial value is not included in the given possible values.
|
295
|
-
def in_array?(key, values)
|
296
|
-
raise_error(type: "array.in", key: key, supposed: values, value: datas[key]) unless (values.empty? or values.include?(datas[key]))
|
297
|
-
end
|
298
|
-
|
299
|
-
# Checks if the value associated with the given key is equal to the given value.
|
300
|
-
# @param [Object] key the key associated with the value to check.
|
301
|
-
# @param [Object] value the values with which the initial value should be compared.
|
302
|
-
# @raise [ArgumentError] if the initial value is not equal to the given value.
|
303
|
-
def equals_to?(key, value)
|
304
|
-
raise_error(type: "equals", key: key, supposed: value, found: datas[key]) unless datas[key] == value
|
305
|
-
end
|
306
|
-
|
307
|
-
# Checks if the value associated with the given key is equal to the given key.
|
308
|
-
# @param [Object] key the key associated with the value to check.
|
309
|
-
# @param [Object] value the key to compare the currently validated key with.
|
310
|
-
# @raise [ArgumentError] if the initial value is not equal to the given value.
|
311
|
-
def equals_key?(key, value)
|
312
|
-
raise_error(type: "equals", key: key, supposed: datas[value], found: datas[key]) unless datas[key] == datas[value]
|
313
|
-
end
|
314
|
-
|
315
|
-
# Checks if the value associated with the given key has the given required keys.
|
316
|
-
# @param [Object] key the key associated with the value to check.
|
317
|
-
# @param [Array] required_keys the keys that the initial Hash typed value should contain.
|
318
|
-
# @raise [ArgumentError] if the initial value has not each and every one of the given keys.
|
319
|
-
def has_keys?(key, required_keys)
|
320
|
-
raise_error(type: "contains.keys", required: required_keys, key: key) if (datas[key].keys & required_keys) != required_keys
|
321
|
-
end
|
322
|
-
|
323
|
-
# Checks if the value associated with the given key has the given required values.
|
324
|
-
# @param [Object] key the key associated with the value to check.
|
325
|
-
# @param [Array] required_values the values that the initial Enumerable typed value should contain.
|
326
|
-
# @raise [ArgumentError] if the initial value has not each and every one of the given values.
|
327
|
-
def contains?(key, values, required_values)
|
328
|
-
raise_error(type: "contains.values", required: required_values, key: key) if (values & required_values) != required_values
|
329
|
-
end
|
330
|
-
|
331
|
-
def match_regex?(key, value, regex)
|
332
|
-
regex = Regexp.new(regex) if regex.kind_of?(String)
|
333
|
-
raise_error(type: "regex", regex: regex, value: value, key: key) unless regex.match(value)
|
334
|
-
end
|
335
|
-
|
336
|
-
# Check if the value associated with the given key matches the given regular expression.
|
337
|
-
# @param [Object] key the key of the value to compare with the given regexp.
|
338
|
-
# @param [Regexp] regex the regex with which match the initial value.
|
339
|
-
# @return [Boolean] true if the initial value matches the regex, false if not.
|
340
|
-
def match?(key, regex)
|
341
|
-
return (!datas.has_key?(key) or datas[key].to_s.match(regex))
|
342
|
-
end
|
343
|
-
|
344
|
-
# Check if the value associated with the given key is typed with the given type, or with a type inheriting from it.
|
345
|
-
# @param [Object] key the key of the value to check the type from.
|
346
|
-
# @param [Class] type the type with which check the initial value.
|
347
|
-
# @return [Boolean] true if the initial value is from the right type, false if not.
|
348
|
-
def is_typed?(key, type)
|
349
|
-
return (!datas.has_key?(key) or datas[key].kind_of?(type))
|
350
|
-
end
|
351
|
-
|
352
|
-
# Transforms a given value in a boolean.
|
353
|
-
# @param [Object] value the value to transform into a boolean.
|
354
|
-
# @return [Boolean] true if the value was true, 1 or yes, false if not.
|
355
|
-
def to_boolean(value)
|
356
|
-
["true", "1", "yes"].include?(value.to_s) ? true : false
|
357
|
-
end
|
358
|
-
|
359
|
-
# Tries to store the associated key in the filtered key, transforming it with the given process.
|
360
|
-
# @param [Object] key the key associated with the value to store in the filtered datas.
|
361
|
-
# @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
|
362
|
-
# @param [Hash] options the options applied to the initial value.
|
363
|
-
def store(key, process, options = {})
|
364
|
-
unless (options.has_key?(:extract) and options[:extract] == false)
|
365
|
-
if datas.has_key?(key)
|
366
|
-
value = ((options.has_key?(:cast) and options[:cast] == false) ? datas[key] : process.call(datas[key]))
|
367
|
-
if(options.has_key?(:in))
|
368
|
-
in_array?(key, options[:in])
|
369
|
-
elsif(options.has_key?(:equals))
|
370
|
-
equals_to?(key, options[:equals])
|
371
|
-
elsif(options.has_key?(:equals_key))
|
372
|
-
equals_key?(key, options[:equals_key])
|
373
|
-
end
|
374
|
-
options.has_key?(:rename) ? (@filtered[options[:rename]] = value) : (@filtered[key] = value)
|
375
|
-
end
|
376
|
-
end
|
377
|
-
end
|
378
|
-
|
379
|
-
# Parses a box given as a string of four numbers separated by commas.
|
380
|
-
# @param [String] box the string representing the box.
|
381
|
-
# @return [Array] an array of size 2, containing two arrays of size 2 (the first being the coordinates of the top-left corner, the second the ones of the bottom-right corner)
|
382
|
-
def parse_box(key, box)
|
383
|
-
if box.kind_of?(String)
|
384
|
-
begin
|
385
|
-
raw_box = box.split(",").map(&:to_f)
|
386
|
-
box = [[raw_box[0], raw_box[1]], [raw_box[2], raw_box[3]]]
|
387
|
-
rescue
|
388
|
-
raise_error(type: "box.format", key: "key", value: box)
|
389
|
-
end
|
390
|
-
end
|
391
|
-
return box
|
392
|
-
end
|
393
|
-
|
394
|
-
# Verify if a box contains another box.
|
395
|
-
# @param [Object] container any object that can be treated as a box, container of the other box
|
396
|
-
# @param [Object] contained any object that can be treated as a box, contained in the other box
|
397
|
-
# @return [Boolean] TRUE if the box is contained in the other one, FALSE if not.
|
398
|
-
def box_contains?(key, container, contained)
|
399
|
-
container = parse_box(key, container)
|
400
|
-
contained = parse_box(key, contained)
|
401
|
-
result = ((container[0][0] <= contained[0][0]) and (container[0][1] <= container[0][1]) and (container[1][0] >= container[1][0]) and (container[1][1] >= container[1][1]))
|
402
|
-
raise_error(type: "box.containment", contained: contained, container: container, key: key) unless result
|
403
|
-
end
|
404
|
-
|
405
|
-
# Raises a type error with a generic message.
|
406
|
-
# @param [Object] key the key associated from the value triggering the error.
|
407
|
-
# @param [Class] type the expected type, not respected by the initial value.
|
408
|
-
# @raise [ArgumentError] the chosen type error.
|
409
|
-
def raise_type_error(key, type)
|
410
|
-
raise_error(type: "type", key: key, supposed: type, found: key.class)
|
411
|
-
end
|
412
|
-
|
413
|
-
protected
|
414
|
-
|
415
|
-
# Raises an error giving a message to display.
|
416
|
-
# @param [String] message the the message to display with the exception.
|
417
|
-
# @raise ArgumentError an error to stop the execution when this method is invoked.
|
418
|
-
def raise_error(message)
|
419
|
-
handler.report_error(message)
|
420
|
-
end
|
421
|
-
|
422
|
-
# Accessor for the errors, use only if the handler is a Kharon::Handlers::Messages.
|
423
|
-
# @return [Array] the errors encountered during validation or an empty array if the handler was a Kharon::Handlers::Exceptions.
|
424
|
-
def errors
|
425
|
-
handler.respond_to?(:errors) ? handler.errors : []
|
61
|
+
processors[:hash].process(key, options)
|
426
62
|
end
|
427
63
|
|
428
64
|
end
|