kharon 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c25325fecde2ed9bb57cc60983980dba2b50f700
4
+ data.tar.gz: 46a7a17a5075d66e9552eb083d8428edb428147f
5
+ SHA512:
6
+ metadata.gz: 9e5ed5dc943275d41234da3c1c36507968b11df77dd0403e2553b2362a6959561990231cc155b0d572f586fffffc2c1265b0a67eb623957fb4b6c8c3296bdc5b
7
+ data.tar.gz: c6a47f792e0644c6bae66269352d167c4b770f043a133e5481dacd6a8ce1eebe02390abbe7606315645bda4f2f629fbcc64c4dad7f01ea036c30b2f73a432083
@@ -0,0 +1,15 @@
1
+ module Charon
2
+ module Helpers
3
+
4
+ # Validates the datas passed as parameter with a Phenix::Validator and the given instructions.
5
+ # @param [Hash] the parameters to validate with the given instructions.
6
+ # @param [Proc] the instructions to apply on the validator.
7
+ # @return [Hash] the validated and filtered datas.
8
+ def validate(datas, &block)
9
+ validator = Phenix::Validator.new(datas)
10
+ validator.instance_eval(&block)
11
+ return validator.filtered
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,272 @@
1
+ require "pry"
2
+
3
+ module Charon
4
+ # The validator uses aquarium as an AOP DSL to provide "before" and "after" joint point to its main methods.
5
+ # @author Vincent Courtois <vincent.courtois@mycar-innovations.com>
6
+ class Validator
7
+ include Aquarium::DSL
8
+
9
+ # @!attribute [r] datas
10
+ # @return The datas to filter, they shouldn't be modified to guarantee their integrity.
11
+ attr_reader :datas
12
+
13
+ # @!attribute [rw] filtered
14
+ # @return The filtered datas are the datas after they have been filtered (renamed keys for example) by the validator.
15
+ attr_accessor :filtered
16
+
17
+ # Constructor of the classe, receiving the datas to validate and filter.
18
+ # @param [Hash] datas the datas to validate in the validator.
19
+ def initialize(datas)
20
+ @datas = datas
21
+ @filtered = Hash.new
22
+ end
23
+
24
+ # @!group Public_interface
25
+
26
+ # Checks if the given key is an integer or not.
27
+ # @param [Object] key the key about which verify the type.
28
+ # @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
29
+ def integer(key, options = {})
30
+ match?(key, /\A\d+\Z/) ? store(key, ->(item){item.to_i}, options) : raise_type_error(key, "Integer")
31
+ end
32
+
33
+ # Checks if the given key is a numeric or not.
34
+ # @param [Object] key the key about which verify the type.
35
+ # @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
36
+ def numeric(key, options = {})
37
+ match?(key, /\A([+-]?\d+)([,.](\d+))?\Z/) ? store(key, ->(item){item.sub(/,/, ".").to_f}, options) : raise_type_error(key, "Numeric")
38
+ end
39
+
40
+ # Checks if the given key is a not-empty string or not.
41
+ # @param [Object] key the key about which verify the type.
42
+ # @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
43
+ def text(key, options = {})
44
+ is_typed?(key, String) ? store(key, ->(item){item.to_s}, options) : raise_type_error(key, "String")
45
+ end
46
+
47
+ # Doesn't check the type of the key and let it pass without modification.
48
+ # @param [Object] key the key about which verify the type.
49
+ # @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
50
+ def any(key, options = {})
51
+ store(key, ->(item){item}, options)
52
+ end
53
+
54
+ # Checks if the given key is a datetime or not.
55
+ # @param [Object] key the key about which verify the type.
56
+ # @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
57
+ def datetime(key, options = {})
58
+ begin; store(key, ->(item){DateTime.parse(item.to_s)} , options); rescue; raise_type_error(key, "DateTime"); end
59
+ end
60
+
61
+ # Checks if the given key is a date or not.
62
+ # @param [Object] key the key about which verify the type.
63
+ # @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
64
+ def date(key, options = {})
65
+ begin; store(key, ->(item){Date.parse(item.to_s)}, options); rescue; raise_type_error(key, "Date"); end
66
+ end
67
+
68
+ # Checks if the given key is an array or not.
69
+ # @param [Object] key the key about which verify the type.
70
+ # @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
71
+ def array(key, options = {})
72
+ is_typed?(key, Array) ? store(key, ->(item){item.to_a}, options) : raise_type_error(key, "Array")
73
+ end
74
+
75
+ # Checks if the given key is a hash or not.
76
+ # @param [Object] key the key about which verify the type.
77
+ # @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
78
+ def hash(key, options = {})
79
+ is_typed?(key, Hash) ? store(key, ->(item){item.to_h}, options) : raise_type_error(key, "Hash")
80
+ end
81
+
82
+ # Checks if the given key is a boolean or not.
83
+ # @param [Object] key the key about which verify the type.
84
+ # @param [Hash] options a hash of options passed to this method (see documentation to know which options pass).
85
+ def boolean(key, options = {})
86
+ match?(key, /(true)|(false)/) ? store(key, ->(item){to_boolean(item)}, options) : raise_type_error(key, "Numeric")
87
+ end
88
+
89
+ # Checks if the given key is a SSID for a MongoDB object 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
+ def ssid(key, options = {})
93
+ 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")
94
+ end
95
+
96
+ # @!endgroup Public_interface
97
+
98
+ # @!group Advices
99
+
100
+ # Before advice checking for "required", "dependency", and "dependencies" options.
101
+ before calls_to: self.instance_methods(false), exclude_methods: [:initialize, :new, :required, :dependency, :dependencies] do |joint_point, validator, *args|
102
+ unless !defined?(args[1]) or args[1].nil? or args[1].empty?
103
+ validator.required(args[0]) if (args[1].has_key?(:required) and args[1][:required] == true)
104
+ if args[1].has_key?(:dependencies)
105
+ validator.dependencies(args[0], args[1][:dependencies])
106
+ elsif args[1].has_key?(:dependency)
107
+ validator.dependency(args[0], args[1][:dependency])
108
+ end
109
+ end
110
+ end
111
+
112
+ # After advice checking in numerics if limits are given, and if there are, if they are respected.
113
+ after calls_to: [:integer, :numeric] do |joint_point, validator, *args|
114
+ unless !defined?(args[1]) or args[1].nil? or args[1].empty?
115
+ if(args[1].has_key?(:between))
116
+ validator.check_min_value(args[0], args[1][:between][0])
117
+ validator.check_max_value(args[0], args[1][:between][1])
118
+ else
119
+ validator.check_min_value(args[0], args[1][:min]) if(args[1].has_key?(:min))
120
+ validator.check_max_value(args[0], args[1][:max]) if(args[1].has_key?(:max))
121
+ end
122
+ end
123
+ end
124
+
125
+ # After advcie for all methods, checking the "in" and "equals" options.
126
+ after calls_to: self.instance_methods(false), exclude_methods: [:initialize, :new, :required, :dependency, :dependencies] do |joint_point, validator, *args|
127
+ unless !defined?(args[1]) or args[1].nil? or args[1].empty?
128
+ if(args[1].has_key?(:in))
129
+ validator.in_array?(args[0], args[1][:in])
130
+ elsif(args[1].has_key?(:equals))
131
+ validator.equals_to?(args[0], args[1][:equals])
132
+ end
133
+ end
134
+ end
135
+
136
+ # After advice for hashes, checking the "has_keys" and "contains" options.
137
+ after calls_to: [:hash] do |joint_point, validator, *args|
138
+ unless !defined?(args[1]) or args[1].nil? or args[1].empty?
139
+ validator.has_keys?(args[0], args[1][:has_keys]) if(args[1].has_key?(:has_keys))
140
+ validator.contains?(args[0], validator.datas[args[0]].values, args[1][:contains]) if(args[1].has_key?(:contains))
141
+ end
142
+ end
143
+
144
+ # After advice for arrays, checking the "contains" option.
145
+ after calls_to: [:array] do |joint_point, validator, *args|
146
+ unless !defined?(args[1]) or args[1].nil? or args[1].empty?
147
+ validator.contains?(args[0], validator.datas[args[0]], args[1][:contains]) if(args[1].has_key?(:contains))
148
+ end
149
+ end
150
+
151
+ # @!endgroup Advices
152
+
153
+ # Checks if a required key is present in provided datas.
154
+ # @param [Object] key the key of which check the presence.
155
+ # @raise [ArgumentError] if the key is not present.
156
+ def required(key)
157
+ raise ArgumentError.new("The key #{key} is required and not provided.") unless @datas.has_key?(key)
158
+ end
159
+
160
+ # Syntaxic sugar used to chack several dependencies at once.
161
+ # @param [Object] key the key needing another key to properly work.
162
+ # @param [Object] dependency the key needed by another key for it to properly work.
163
+ # @raise [ArgumentError] if the required dependencies are not present.
164
+ # @see self#check_dependency the associated singular method.
165
+ def dependencies(key, dependencies)
166
+ dependencies.each { |dependency| dependency(key, dependency) }
167
+ end
168
+
169
+ # Checks if a dependency is respected. A dependency is a key openly needed by another key.
170
+ # @param [Object] key the key needing another key to properly work.
171
+ # @param [Object] dependency the key needed by another key for it to properly work.
172
+ # @raise [ArgumentError] if the required dependency is not present.
173
+ def dependency(key, dependency)
174
+ raise ArgumentError.new("The key #{key} needs the key #{dependency} but it was not provided.") unless @datas.has_key?(dependency)
175
+ end
176
+
177
+ # Checks if the value associated with the given key is greater than the given minimum value.
178
+ # @param [Object] key the key associated with the value to compare.
179
+ # @param [Numeric] min_value the required minimum value.
180
+ # @raise [ArgumentError] if the initial value is strictly lesser than the minimum value.
181
+ def check_min_value(key, min_value)
182
+ raise ArgumentError.new("The key #{key} was supposed to be greater or equal than #{min_value}, the value was #{datas[key]}") unless datas[key].to_i >= min_value.to_i
183
+ end
184
+
185
+ # Checks if the value associated with the given key is lesser than the given maximum value.
186
+ # @param [Object] key the key associated with the value to compare.
187
+ # @param [Numeric] max_value the required maximum value.
188
+ # @raise [ArgumentError] if the initial value is strictly greater than the minimum value.
189
+ def check_max_value(key, max_value)
190
+ raise ArgumentError.new("The key #{key} was supposed to be lesser or equal than #{max_value}, the value was #{datas[key]}") unless datas[key].to_i <= max_value.to_i
191
+ end
192
+
193
+ # Checks if the value associated with the given key is included in the given array of values.
194
+ # @param [Object] key the key associated with the value to check.
195
+ # @param [Array] values the values in which the initial value should be contained.
196
+ # @raise [ArgumentError] if the initial value is not included in the given possible values.
197
+ def in_array?(key, values)
198
+ raise ArgumentError.new("The key #{key} was supposed to be in [#{values.join(", ")}], the value was #{datas[key]}") unless (values.empty? or values.include?(datas[key]))
199
+ end
200
+
201
+ # Checks if the value associated with the given key is equal to the given value.
202
+ # @param [Object] key the key associated with the value to check.
203
+ # @param [Object] value the values with which the initial value should be compared.
204
+ # @raise [ArgumentError] if the initial value is not equal to the given value.
205
+ def equals_to?(key, value)
206
+ raise ArgumentError.new("The key #{key} was supposed to equal than #{value}, the value was #{datas[key]}") unless datas[key] == value
207
+ end
208
+
209
+ # Checks if the value associated with the given key has the given required keys.
210
+ # @param [Object] key the key associated with the value to check.
211
+ # @param [Array] required_keys the keys that the initial Hash typed value should contain.
212
+ # @raise [ArgumentError] if the initial value has not each and every one of the given keys.
213
+ def has_keys?(key, required_keys)
214
+ raise ArgumentError.new("The key #{key} was supposed to contains keys [#{required_keys.join(", ")}]") if (datas[key].keys & required_keys) != required_keys
215
+ end
216
+
217
+ # Checks if the value associated with the given key has the given required values.
218
+ # @param [Object] key the key associated with the value to check.
219
+ # @param [Array] required_keys the values that the initial Enumerable typed value should contain.
220
+ # @raise [ArgumentError] if the initial value has not each and every one of the given values.
221
+ def contains?(key, values, required_values)
222
+ raise ArgumentError.new("The key #{key} was supposed to contains values [#{required_values.join(", ")}]") if (values & required_values) != required_values
223
+ end
224
+
225
+ private
226
+
227
+ # Check if the value associated with the given key matches the given regular expression.
228
+ # @param [Object] key the key of the value to compare with the given regexp.
229
+ # @param [Regexp] regex the regex with which match the initial value.
230
+ # @return [Boolean] true if the initial value matches the regex, false if not.
231
+ def match?(key, regex)
232
+ return (!datas.has_key?(key) or datas[key].to_s.match(regex))
233
+ end
234
+
235
+ # Check if the value associated with the given key is typed with the given type, or with a type inheriting from it.
236
+ # @param [Object] key the key of the value to check the type from.
237
+ # @param [Class] type the type with which check the initial value.
238
+ # @return [Boolean] true if the initial value is from the right type, false if not.
239
+ def is_typed?(key, type)
240
+ return (!datas.has_key?(key) or datas[key].kind_of?(type))
241
+ end
242
+
243
+ # Tries to store the associated key in the filtered key, transforming it with the given process.
244
+ # @param [Object] key the key associated with the value to store in the filtered datas.
245
+ # @param [Proc] process a process (lambda) to execute on the initial value. Must contain strictly one argument.
246
+ # @param [Hash] options the options applied to the initial value. Only the option "rename" is checked and executed here.
247
+ def store(key, process, options = {})
248
+ unless (options.has_key?(:extract) and options[:extract] == false)
249
+ if datas.has_key?(key)
250
+ value = ((options.has_key?(:cast) and options[:cast] == false) ? datas[key] : process.call(datas[key]))
251
+ options.has_key?(:rename) ? (@filtered[options[:rename]] = value) : (@filtered[key] = value)
252
+ end
253
+ end
254
+ end
255
+
256
+ # Raises a type error with a generic message.
257
+ # @param [Object] key the key associated from the value triggering the error.
258
+ # @param [Class] type the expected type, not respected by the initial value.
259
+ # @raise [ArgumentError] the chosen type error.
260
+ def raise_type_error(key, type)
261
+ raise ArgumentError.new("The key {key} was supposed to be an instance of #{type}, #{key.class} found.")
262
+ end
263
+
264
+ # Transforms a given value in a boolean.
265
+ # @param [Object] value the value to transform into a boolean.
266
+ # @return [Boolean] true if the value was true, 1 or yes, false if not.
267
+ def to_boolean(value)
268
+ ["true", "1", "yes"].include?(value.to_s) ? true : false
269
+ end
270
+
271
+ end
272
+ end
@@ -0,0 +1,437 @@
1
+ require 'spec_helper'
2
+ require './lib/validator.rb'
3
+
4
+ shared_examples "options" do |process|
5
+ context ":rename" do
6
+ it "correctly renames a key when the value is valid" do
7
+ validator = Charon::Validator.new(valid_datas)
8
+ validator.send(process, valid_datas.keys.first, rename: :another_name)
9
+ expect(validator.filtered[:another_name]).to eq(valid_filtered[valid_datas.keys.first])
10
+ end
11
+
12
+ it "correctly doesn't rename a key when the value is invalid" do
13
+ validator = Charon::Validator.new(invalid_datas)
14
+ expect(->{validator.send(process, invalid_datas.keys.first, rename: :another_name)}).to raise_error(ArgumentError)
15
+ end
16
+ end
17
+
18
+ context ":dependency" do
19
+ it "succeeds when a dependency is given as a key and respected" do
20
+ validator = Charon::Validator.new(valid_datas.merge({dep: "anything"}))
21
+ validator.send(process, valid_datas.keys.first, dependency: :dep)
22
+ expect(validator.filtered).to eq(valid_filtered)
23
+ end
24
+
25
+ it "fails when a dependency is not respected" do
26
+ validator = Charon::Validator.new(valid_datas)
27
+ expect(->{validator.send(process, valid_datas.keys.first, dependency: :another_key_not_existing)}).to raise_error(ArgumentError)
28
+ end
29
+ end
30
+
31
+ context ":dependencies" do
32
+ it "succeeds when dependencies are given as an array and respected" do
33
+ validator = Charon::Validator.new(valid_datas.merge({dep1: "something", dep2: "something else"}))
34
+ validator.send(process, valid_datas.keys.first, dependencies: [:dep1, :dep2])
35
+ expect(validator.filtered).to eq(valid_filtered)
36
+ end
37
+
38
+ it "fails when one of the dependencies is not respected" do
39
+ validator = Charon::Validator.new(valid_datas.merge({dep1: "anything"}))
40
+ expect(->{validator.send(process, valid_datas.keys.first, dependencies: [:dep1, :dep2])}).to raise_error(ArgumentError)
41
+ end
42
+ end
43
+
44
+ context ":required" do
45
+ it "succeeds when a not required key is not given, but filters nothing" do
46
+ validator = Charon::Validator.new(valid_datas)
47
+ validator.send(process, :not_required_key)
48
+ expect(validator.filtered).to be_empty
49
+ end
50
+
51
+ it "suceeds when a key has a required option to false, and is not given, but filters nothing" do
52
+ validator = Charon::Validator.new(valid_datas)
53
+ validator.send(process, :not_in_hash, required: false)
54
+ expect(validator.filtered).to be_empty
55
+ end
56
+
57
+ it "fails when a required key is not given" do
58
+ validator = Charon::Validator.new(valid_datas)
59
+ expect(->{validator.send(process, :not_in_hash, required: true)}).to raise_error(ArgumentError)
60
+ end
61
+ end
62
+
63
+ context ":in" do
64
+ it "succeeds when the value is effectively in the possible values" do
65
+ validator = Charon::Validator.new(valid_datas)
66
+ validator.send(process, valid_datas.keys.first, :in => [valid_datas[valid_datas.keys.first], "another random data"])
67
+ expect(validator.filtered).to eq(valid_filtered)
68
+ end
69
+
70
+ it "succeeds if there are no values" do
71
+ validator = Charon::Validator.new(valid_datas)
72
+ validator.send(process, valid_datas.keys.first, :in => [])
73
+ expect(validator.filtered).to eq(valid_filtered)
74
+ end
75
+
76
+ it "fails if the value is not in the possible values" do
77
+ validator = Charon::Validator.new(valid_datas)
78
+ expect(->{validator.send(process, valid_datas.keys.first, :in => ["anything but the value", "another impossible thing"])}).to raise_error(ArgumentError)
79
+ end
80
+ end
81
+
82
+ context ":equals" do
83
+ it "succeeds when the value is equal to the given value" do
84
+ validator = Charon::Validator.new(valid_datas)
85
+ validator.send(process, valid_datas.keys.first, :equals => valid_datas[valid_datas.keys.first])
86
+ expect(validator.filtered).to eq(valid_filtered)
87
+ end
88
+
89
+ it "fails if the value is not equal to the given value" do
90
+ validator = Charon::Validator.new(valid_datas)
91
+ expect(->{validator.send(process, valid_datas.keys.first, :equals => "anything but the given value")}).to raise_error(ArgumentError)
92
+ end
93
+ end
94
+
95
+ context ":extract" do
96
+ it "etracts the data when given at true" do
97
+ validator = Charon::Validator.new(valid_datas)
98
+ validator.send(process, valid_datas.keys.first, :extract => false)
99
+ expect(validator.filtered).to eq({})
100
+ end
101
+
102
+ it "doesn't extract the data when given at false" do
103
+ validator = Charon::Validator.new(valid_datas)
104
+ validator.send(process, valid_datas.keys.first, :extract => true)
105
+ expect(validator.filtered).to eq(valid_filtered)
106
+ end
107
+ end
108
+
109
+ context ":cast" do
110
+ it "casts the data when given at true" do
111
+ validator = Charon::Validator.new(valid_datas)
112
+ validator.send(process, valid_datas.keys.first, :cast => true)
113
+ expect(validator.filtered).to eq(valid_filtered)
114
+ end
115
+
116
+ it "doesn't cast the data when given at false" do
117
+ validator = Charon::Validator.new(valid_datas)
118
+ validator.send(process, valid_datas.keys.first, :cast => false)
119
+ expect(validator.filtered).to eq(valid_datas)
120
+ end
121
+ end
122
+ end
123
+
124
+ shared_examples "type checker" do |type, process|
125
+ it "succeeds when given an instance of #{type}" do
126
+ validator = Charon::Validator.new(valid_datas)
127
+ validator.send(process, valid_datas.keys.first)
128
+ expect(validator.filtered).to eq(valid_filtered)
129
+ end
130
+
131
+ it "fails when given something else than an instance of #{type}" do
132
+ validator = Charon::Validator.new(invalid_datas)
133
+ expect(->{validator.send(process, invalid_datas.keys.first)}).to raise_error(ArgumentError)
134
+ end
135
+ end
136
+
137
+ shared_examples "min/max checker" do |process, key, transformation|
138
+ let(:value) { valid_datas[key].send(transformation) }
139
+ let(:validator) { Charon::Validator.new(valid_datas) }
140
+
141
+ context ":min" do
142
+ it "succeeds when a min option is given, and the value is strictly greater than it" do
143
+ validator.send(process, key, {min: value-1})
144
+ expect(validator.filtered).to eq(valid_filtered)
145
+ end
146
+
147
+ it "succeeds when a min option is given, and the value is equal to it" do
148
+ validator.send(process, key, {min: value})
149
+ expect(validator.filtered).to eq(valid_filtered)
150
+ end
151
+
152
+ it "fails when a min option is given, but not respected" do
153
+ expect(->{validator.send(process, key, {min: value+1})}).to raise_error(ArgumentError)
154
+ end
155
+ end
156
+
157
+ context ":max" do
158
+ it "succeeds when a max option is given, and the value is strictly lesser than it" do
159
+ validator.send(process, key, {max: value+1})
160
+ expect(validator.filtered).to eq(valid_filtered)
161
+ end
162
+
163
+ it "succeeds when a max option is given, and the value is equal to it" do
164
+ validator.send(process, key, {max: value})
165
+ expect(validator.filtered).to eq(valid_filtered)
166
+ end
167
+
168
+ it "fails when a max option is given, but not respected" do
169
+ expect(->{validator.send(process, key, {max: value-1})}).to raise_error(ArgumentError)
170
+ end
171
+ end
172
+
173
+ context ":between" do
174
+
175
+ it "succeeds when a between option is given, and respected" do
176
+ validator.send(process, key, {between: [value-1, value+1]})
177
+ expect(validator.filtered).to eq(valid_filtered)
178
+ end
179
+
180
+ it "fails when a max between option is given, but the value is strictly lesser" do
181
+ expect(->{validator.send(process, key, {between: [value+1, value+2]})}).to raise_error(ArgumentError)
182
+ end
183
+
184
+ it "fails when a max between option is given, but the value is strictly greater" do
185
+ expect(->{validator.send(process, key, {between: [value-2, value-1]})}).to raise_error(ArgumentError)
186
+ end
187
+
188
+ it "fails when a max between option is given, but the value is equal to the inferior limit" do
189
+ validator.send(process, key, {between: [value, value+1]})
190
+ expect(validator.filtered).to eq(valid_filtered)
191
+ end
192
+
193
+ it "fails when a max between option is given, but the value is equal to the superio limit" do
194
+ validator.send(process, key, {between: [value-1, value]})
195
+ expect(validator.filtered).to eq(valid_filtered)
196
+ end
197
+ end
198
+ end
199
+
200
+ shared_examples "contains option" do |process, key|
201
+ context ":contains" do
202
+ it "succeeds if all values are contained" do
203
+ validator = Charon::Validator.new(valid_datas)
204
+ validator.send(process, key, contains: ["val1", "val2"])
205
+ expect(validator.filtered).to eq(valid_filtered)
206
+ end
207
+
208
+ it "fails if only some values are contained" do
209
+ validator = Charon::Validator.new(valid_datas)
210
+ expect(->{validator.send(process, key, contains: ["val1", "val3"])}).to raise_error(ArgumentError)
211
+ end
212
+
213
+ it "fails if none of the values are contained" do
214
+ validator = Charon::Validator.new(valid_datas)
215
+ expect(->{validator.send(process, key, contains: ["val3", "val4"])}).to raise_error(ArgumentError)
216
+ end
217
+ end
218
+ end
219
+
220
+ describe "Validator" do
221
+ context "integer" do
222
+ let(:valid_datas) { {is_an_integer: "1000"} }
223
+ let(:valid_filtered) { {is_an_integer: 1000} }
224
+ let(:invalid_datas) { {is_not_an_integer: "something else"} }
225
+
226
+ it "succeeds when given an integer" do
227
+ validator = Charon::Validator.new(valid_datas)
228
+ validator.integer(:is_an_integer)
229
+ expect(validator.filtered).to eq(valid_filtered)
230
+ end
231
+
232
+ it "fails when given a float" do
233
+ validator = Charon::Validator.new({is_not_an_integer: 1000.5})
234
+ expect(->{validator.integer(:is_not_an_integer)}).to raise_error(ArgumentError)
235
+ end
236
+
237
+ it "fails when not given a numeric" do
238
+ validator = Charon::Validator.new(invalid_datas)
239
+ expect(->{validator.integer(:is_not_an_integer)}).to raise_error(ArgumentError)
240
+ end
241
+
242
+ context "options" do
243
+ include_examples "options", :integer
244
+ include_examples "min/max checker", :integer, :is_an_integer, :to_i
245
+ end
246
+ end
247
+
248
+ context "numeric" do
249
+ let(:valid_datas) { {is_a_double: "1000.5"} }
250
+ let(:valid_filtered) { {is_a_double: 1000.5} }
251
+ let(:invalid_datas) { {is_not_a_numeric: "something else"} }
252
+
253
+ it "succeeds when given an integer" do
254
+ validator = Charon::Validator.new({is_an_integer: "1000"})
255
+ validator.numeric(:is_an_integer)
256
+ expect(validator.filtered).to eq({is_an_integer: 1000})
257
+ end
258
+
259
+ it "succeeds when given an decimal number with a dot" do
260
+ validator = Charon::Validator.new(valid_datas)
261
+ validator.numeric(:is_a_double)
262
+ expect(validator.filtered).to eq(valid_filtered)
263
+ end
264
+
265
+ it "succeeds when given an decimal number with a comma" do
266
+ validator = Charon::Validator.new({is_a_double: "1000,5"})
267
+ validator.numeric(:is_a_double)
268
+ expect(validator.filtered).to eq(valid_filtered)
269
+ end
270
+
271
+ it "fails when not given a numeric" do
272
+ validator = Charon::Validator.new(invalid_datas)
273
+ expect(->{validator.integer(:is_not_a_numeric)}).to raise_error(ArgumentError)
274
+ end
275
+
276
+ context "options" do
277
+ include_examples "options", :numeric
278
+ include_examples "min/max checker", :numeric, :is_a_double, :to_f
279
+ end
280
+ end
281
+
282
+ context "text" do
283
+ let(:valid_datas) { {is_a_string: "something"} }
284
+ let(:valid_filtered) { {is_a_string: "something"} }
285
+ let(:invalid_datas) { {is_not_a_string: 1000} }
286
+
287
+ include_examples "type checker", "String", :text
288
+
289
+ context "options" do
290
+ include_examples "options", :text
291
+ end
292
+ end
293
+
294
+ context "datetime" do
295
+ let(:date_time) { DateTime.new }
296
+ let(:valid_datas) { {is_a_datetime: date_time.to_s} }
297
+ let(:valid_filtered) { {is_a_datetime: date_time} }
298
+ let(:invalid_datas) { {is_not_a_datetime: "something else"} }
299
+
300
+ it "succeeds when given a valid datetime as a string" do
301
+ validator = Charon::Validator.new(valid_datas)
302
+ validator.datetime(:is_a_datetime)
303
+ expect(validator.filtered).to eq(valid_filtered)
304
+ end
305
+
306
+ it "succeeds when given a valid datetime as a DateTime Object" do
307
+ validator = Charon::Validator.new(valid_filtered)
308
+ validator.datetime(:is_a_datetime)
309
+ expect(validator.filtered).to eq(valid_filtered)
310
+ end
311
+
312
+ it "fails when given something else than a valid datetime" do
313
+ validator = Charon::Validator.new(invalid_datas)
314
+ expect(->{validator.datetime(:is_not_a_datetime)}).to raise_error(ArgumentError)
315
+ end
316
+
317
+ context "options" do
318
+ include_examples "options", :datetime
319
+ end
320
+ end
321
+
322
+ context "date" do
323
+ let(:date) { Date.new }
324
+ let(:valid_datas) { {is_a_date: date.to_s} }
325
+ let(:valid_filtered) { {is_a_date: date} }
326
+ let(:invalid_datas) { {is_not_a_date: "something else"} }
327
+
328
+ it "succeeds when given a valid date as a string" do
329
+ validator = Charon::Validator.new(valid_datas)
330
+ validator.date(:is_a_date)
331
+ expect(validator.filtered).to eq(valid_filtered)
332
+ end
333
+
334
+ it "succeeds when given a valid date as a Date Object" do
335
+ validator = Charon::Validator.new(valid_filtered)
336
+ validator.date(:is_a_date)
337
+ expect(validator.filtered).to eq(valid_filtered)
338
+ end
339
+
340
+ it "fails when given something else than a valid date" do
341
+ validator = Charon::Validator.new(invalid_datas)
342
+ expect(->{validator.date(:is_not_a_date)}).to raise_error(ArgumentError)
343
+ end
344
+
345
+ context "options" do
346
+ include_examples "options", :date
347
+ end
348
+ end
349
+
350
+ context "array" do
351
+ let(:valid_datas) { {is_an_array: ["val1", "val2"]} }
352
+ let(:valid_filtered) { {is_an_array: ["val1", "val2"]} }
353
+ let(:invalid_datas) { {is_not_an_array: 1000} }
354
+
355
+ include_examples "type checker", "Array", :array
356
+
357
+ context "options" do
358
+ include_examples "options", :array
359
+ include_examples "contains option", :array, :is_an_array
360
+ end
361
+ end
362
+
363
+ context "hash" do
364
+ let(:valid_datas) { {is_a_hash: {key1: "val1", key2: "val2"}} }
365
+ let(:valid_filtered) { {is_a_hash: {key1: "val1", key2: "val2"}} }
366
+ let(:invalid_datas) { {is_not_a_hash: 1000} }
367
+
368
+ include_examples "type checker", "Hash", :hash
369
+
370
+ context "options" do
371
+ include_examples "options", :hash
372
+ include_examples "contains option", :hash, :is_a_hash
373
+
374
+ context ":has_keys" do
375
+ it "succeeds if all keys are contained in the hash" do
376
+ validator = Charon::Validator.new(valid_datas)
377
+ validator.hash(:is_a_hash, has_keys: [:key1, :key2])
378
+ expect(validator.filtered).to eq(valid_filtered)
379
+ end
380
+
381
+ it "fails if not all keys are given in the hash" do
382
+ validator = Charon::Validator.new(valid_datas)
383
+ expect(->{validator.hash(:is_a_hash, has_keys: [:key1, :key3])}).to raise_error(ArgumentError)
384
+ end
385
+
386
+ it "fails if no keys are contained in the hash" do
387
+ validator = Charon::Validator.new(valid_datas)
388
+ expect(->{validator.hash(:is_a_hash, has_keys: [:key3, :key4])}).to raise_error(ArgumentError)
389
+ end
390
+ end
391
+ end
392
+ end
393
+
394
+ context "boolean" do
395
+ let(:valid_datas) { {is_a_boolean: "true"} }
396
+ let(:valid_filtered) { {is_a_boolean: true} }
397
+ let(:invalid_datas) { {is_not_a_boolean: "anything else"} }
398
+
399
+ it "succeeds when given a boolean" do
400
+ validator = Charon::Validator.new(valid_datas)
401
+ validator.boolean(:is_a_boolean)
402
+ expect(validator.filtered).to eq(valid_filtered)
403
+ end
404
+
405
+ it "fails when not given a boolean" do
406
+ validator = Charon::Validator.new(invalid_datas)
407
+ expect(->{validator.boolean(:is_not_a_boolean)}).to raise_error(ArgumentError)
408
+ end
409
+
410
+ context "options" do
411
+ include_examples "options", :boolean
412
+ end
413
+ end
414
+
415
+ context "ssid" do
416
+ let(:valid_ssid) { BSON::ObjectId.new }
417
+ let(:valid_datas) { {is_a_ssid: valid_ssid.to_s} }
418
+ let(:valid_filtered) { {is_a_ssid: valid_ssid} }
419
+ let(:invalid_datas) { {is_not_a_ssid: "anything else"} }
420
+
421
+ it "succeeds when given a valid SSID" do
422
+ validator = Charon::Validator.new(valid_datas)
423
+ validator.ssid(:is_a_ssid)
424
+ expect(validator.filtered).to eq(valid_filtered)
425
+ end
426
+
427
+ it "fails when not given a SSID" do
428
+ validator = Charon::Validator.new(invalid_datas)
429
+ expect(->{validator.ssid(:is_not_a_ssid)}).to raise_error(ArgumentError)
430
+ end
431
+
432
+ context "options" do
433
+ include_examples "options", :ssid
434
+ end
435
+ end
436
+
437
+ end
@@ -0,0 +1,14 @@
1
+ # Sets the environment variable to test before loading all the files.
2
+ ENV['RACK_ENV'] = 'test'
3
+
4
+ require 'rack/test'
5
+ require 'mocha/api'
6
+ require 'aquarium'
7
+ require 'moped'
8
+
9
+ module RSpec
10
+ configure do |configuration|
11
+ # Configuration rspec to use mocha as mocking API.
12
+ configuration.mock_with :mocha
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kharon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Vincent Courtois
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aquarium
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.1
27
+ description: Charon let you pass or not pass depending if you meet the criterias for
28
+ this... Or not.
29
+ email: vincent.courtois@mycar-innovations.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/validator.rb
35
+ - lib/validate.rb
36
+ - spec/spec_helper.rb
37
+ - spec/lib/validator_spec.rb
38
+ homepage: https://rubygems.org/gems/kharon
39
+ licenses:
40
+ - Apache License 2
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 2.1.0
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 2.1.11
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: Ruby Hash validator
62
+ test_files:
63
+ - spec/spec_helper.rb
64
+ - spec/lib/validator_spec.rb