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.
Files changed (52) hide show
  1. checksums.yaml +5 -13
  2. data/{.rspec → .rspec.old} +0 -0
  3. data/Gemfile +1 -0
  4. data/Gemfile.lock +12 -4
  5. data/dist/kharon-1.1.0.gem +0 -0
  6. data/doc/Kharon.html +384 -6
  7. data/doc/Kharon/Errors.html +1 -1
  8. data/doc/Kharon/Errors/Validation.html +1 -1
  9. data/doc/Kharon/Handlers.html +1 -1
  10. data/doc/Kharon/Handlers/Exceptions.html +1 -1
  11. data/doc/Kharon/Handlers/Messages.html +1 -1
  12. data/doc/Kharon/Processor.html +425 -0
  13. data/doc/Kharon/Processors.html +144 -0
  14. data/doc/Kharon/Processors/ArrayProcessor.html +429 -0
  15. data/doc/Kharon/Processors/BooleanProcessor.html +306 -0
  16. data/doc/Kharon/Processors/BoxProcessor.html +440 -0
  17. data/doc/Kharon/Processors/DateProcessor.html +306 -0
  18. data/doc/Kharon/Processors/DatetimeProcessor.html +306 -0
  19. data/doc/Kharon/Processors/EmailProcessor.html +307 -0
  20. data/doc/Kharon/Processors/HashProcessor.html +431 -0
  21. data/doc/Kharon/Processors/IntegerProcessor.html +441 -0
  22. data/doc/Kharon/Processors/NumericProcessor.html +463 -0
  23. data/doc/Kharon/Processors/SSIDProcessor.html +307 -0
  24. data/doc/Kharon/Processors/TextProcessor.html +430 -0
  25. data/doc/Kharon/Validate.html +17 -5
  26. data/doc/Kharon/Validator.html +198 -1194
  27. data/doc/_index.html +159 -1
  28. data/doc/class_list.html +1 -1
  29. data/doc/file.README.html +15 -4
  30. data/doc/index.html +15 -4
  31. data/doc/method_list.html +135 -39
  32. data/doc/top-level-namespace.html +1 -1
  33. data/kharon.gemspec +4 -2
  34. data/lib/kharon.rb +32 -2
  35. data/lib/kharon/processor.rb +162 -0
  36. data/lib/kharon/processors.rb +6 -0
  37. data/lib/kharon/processors/array_processor.rb +30 -0
  38. data/lib/kharon/processors/boolean_processor.rb +31 -0
  39. data/lib/kharon/processors/box_processor.rb +63 -0
  40. data/lib/kharon/processors/date_processor.rb +21 -0
  41. data/lib/kharon/processors/datetime_processor.rb +21 -0
  42. data/lib/kharon/processors/email_processor.rb +21 -0
  43. data/lib/kharon/processors/hash_processor.rb +31 -0
  44. data/lib/kharon/processors/integer_processor.rb +55 -0
  45. data/lib/kharon/processors/numeric_processor.rb +66 -0
  46. data/lib/kharon/processors/ssid_processor.rb +21 -0
  47. data/lib/kharon/processors/text_processor.rb +30 -0
  48. data/lib/kharon/validate.rb +1 -1
  49. data/lib/kharon/validator.rb +26 -390
  50. data/lib/kharon/version.rb +1 -1
  51. data/spec/results.html +5277 -321
  52. 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
@@ -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, backtrace: exception.backtrace, message: exception.message})
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
@@ -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 = Hash[datas.map { |k, v| [k.to_sym, v] }]
25
- @filtered = Hash.new
26
- @handler = Kharon.errors_handler
27
- end
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
- # Checks if the given key is a date or not.
80
- # @param [Object] key the key about which verify the type.
81
- # @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
82
- # @example Validates a key so it has to be a date, and depends on another key.
83
- # @validator.date(:a_date, dependency: :another_key)
84
- def date(key, options = {})
85
- before_all(key, options)
86
- begin; store(key, ->(item){Date.parse(item.to_s)}, options); rescue; raise_type_error(key, "Date"); end
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
- # Checks if the given key is an array or not.
90
- # @param [Object] key the key about which verify the type.
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
- before_all(key, options)
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