kharon 0.0.2

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.
@@ -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