kharon 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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