livr2 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +45 -0
- data/Readme.md +114 -0
- data/lib/livr.rb +61 -0
- data/lib/livr/aliased_rule.rb +26 -0
- data/lib/livr/rule.rb +21 -0
- data/lib/livr/rules/common.rb +35 -0
- data/lib/livr/rules/meta.rb +200 -0
- data/lib/livr/rules/modifiers.rb +68 -0
- data/lib/livr/rules/numeric.rb +136 -0
- data/lib/livr/rules/special.rb +65 -0
- data/lib/livr/rules/string.rb +150 -0
- data/lib/livr/validator.rb +137 -0
- data/livr2.gemspec +19 -0
- data/spec/01-test_suite_spec.rb +34 -0
- data/spec/02-aliases_spec.rb +21 -0
- data/spec/03-auto_trim_spec.rb +56 -0
- data/spec/04-custom_filters_spec.rb +54 -0
- data/spec/05-rules_replacement_spec.rb +67 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/test_suite/aliases_negative/01-adult_age/aliases.json +12 -0
- data/spec/test_suite/aliases_negative/01-adult_age/errors.json +6 -0
- data/spec/test_suite/aliases_negative/01-adult_age/input.json +11 -0
- data/spec/test_suite/aliases_negative/01-adult_age/rules.json +10 -0
- data/spec/test_suite/aliases_negative/02-address/aliases.json +20 -0
- data/spec/test_suite/aliases_negative/02-address/errors.json +8 -0
- data/spec/test_suite/aliases_negative/02-address/input.json +13 -0
- data/spec/test_suite/aliases_negative/02-address/rules.json +4 -0
- data/spec/test_suite/aliases_negative/03-adult_age_in_user/aliases.json +31 -0
- data/spec/test_suite/aliases_negative/03-adult_age_in_user/errors.json +8 -0
- data/spec/test_suite/aliases_negative/03-adult_age_in_user/input.json +14 -0
- data/spec/test_suite/aliases_negative/03-adult_age_in_user/rules.json +4 -0
- data/spec/test_suite/aliases_positive/01-adult_age/aliases.json +12 -0
- data/spec/test_suite/aliases_positive/01-adult_age/input.json +11 -0
- data/spec/test_suite/aliases_positive/01-adult_age/output.json +10 -0
- data/spec/test_suite/aliases_positive/01-adult_age/rules.json +10 -0
- data/spec/test_suite/aliases_positive/02-address/aliases.json +20 -0
- data/spec/test_suite/aliases_positive/02-address/input.json +13 -0
- data/spec/test_suite/aliases_positive/02-address/output.json +12 -0
- data/spec/test_suite/aliases_positive/02-address/rules.json +4 -0
- data/spec/test_suite/aliases_positive/03-adult_age_in_user/aliases.json +31 -0
- data/spec/test_suite/aliases_positive/03-adult_age_in_user/input.json +14 -0
- data/spec/test_suite/aliases_positive/03-adult_age_in_user/output.json +12 -0
- data/spec/test_suite/aliases_positive/03-adult_age_in_user/rules.json +4 -0
- data/spec/test_suite/negative/01-required/errors.json +5 -0
- data/spec/test_suite/negative/01-required/input.json +10 -0
- data/spec/test_suite/negative/01-required/rules.json +10 -0
- data/spec/test_suite/negative/02-not_empty/errors.json +3 -0
- data/spec/test_suite/negative/02-not_empty/input.json +10 -0
- data/spec/test_suite/negative/02-not_empty/rules.json +10 -0
- data/spec/test_suite/negative/03-one_of/errors.json +11 -0
- data/spec/test_suite/negative/03-one_of/input.json +12 -0
- data/spec/test_suite/negative/03-one_of/rules.json +11 -0
- data/spec/test_suite/negative/04-min_length/errors.json +10 -0
- data/spec/test_suite/negative/04-min_length/input.json +12 -0
- data/spec/test_suite/negative/04-min_length/rules.json +11 -0
- data/spec/test_suite/negative/05-max_length/errors.json +10 -0
- data/spec/test_suite/negative/05-max_length/input.json +12 -0
- data/spec/test_suite/negative/05-max_length/rules.json +11 -0
- data/spec/test_suite/negative/06-length_equal/errors.json +10 -0
- data/spec/test_suite/negative/06-length_equal/input.json +12 -0
- data/spec/test_suite/negative/06-length_equal/rules.json +11 -0
- data/spec/test_suite/negative/07-length_between/errors.json +10 -0
- data/spec/test_suite/negative/07-length_between/input.json +12 -0
- data/spec/test_suite/negative/07-length_between/rules.json +11 -0
- data/spec/test_suite/negative/08-like/errors.json +11 -0
- data/spec/test_suite/negative/08-like/input.json +14 -0
- data/spec/test_suite/negative/08-like/rules.json +12 -0
- data/spec/test_suite/negative/09-integer/errors.json +11 -0
- data/spec/test_suite/negative/09-integer/input.json +13 -0
- data/spec/test_suite/negative/09-integer/rules.json +12 -0
- data/spec/test_suite/negative/10-positive_integer/errors.json +11 -0
- data/spec/test_suite/negative/10-positive_integer/input.json +13 -0
- data/spec/test_suite/negative/10-positive_integer/rules.json +12 -0
- data/spec/test_suite/negative/11-decimal/errors.json +11 -0
- data/spec/test_suite/negative/11-decimal/input.json +13 -0
- data/spec/test_suite/negative/11-decimal/rules.json +12 -0
- data/spec/test_suite/negative/12-positive_decimal/errors.json +11 -0
- data/spec/test_suite/negative/12-positive_decimal/input.json +13 -0
- data/spec/test_suite/negative/12-positive_decimal/rules.json +12 -0
- data/spec/test_suite/negative/13-max_number/errors.json +10 -0
- data/spec/test_suite/negative/13-max_number/input.json +12 -0
- data/spec/test_suite/negative/13-max_number/rules.json +11 -0
- data/spec/test_suite/negative/14-min_number/errors.json +11 -0
- data/spec/test_suite/negative/14-min_number/input.json +13 -0
- data/spec/test_suite/negative/14-min_number/rules.json +12 -0
- data/spec/test_suite/negative/15-number_beetween/errors.json +12 -0
- data/spec/test_suite/negative/15-number_beetween/input.json +14 -0
- data/spec/test_suite/negative/15-number_beetween/rules.json +13 -0
- data/spec/test_suite/negative/16-email/errors.json +12 -0
- data/spec/test_suite/negative/16-email/input.json +14 -0
- data/spec/test_suite/negative/16-email/rules.json +13 -0
- data/spec/test_suite/negative/17-equal_to_field/errors.json +10 -0
- data/spec/test_suite/negative/17-equal_to_field/input.json +12 -0
- data/spec/test_suite/negative/17-equal_to_field/rules.json +11 -0
- data/spec/test_suite/negative/18-nested_object/errors.json +9 -0
- data/spec/test_suite/negative/18-nested_object/input.json +9 -0
- data/spec/test_suite/negative/18-nested_object/rules.json +9 -0
- data/spec/test_suite/negative/19-list_of/errors.json +6 -0
- data/spec/test_suite/negative/19-list_of/input.json +6 -0
- data/spec/test_suite/negative/19-list_of/rules.json +14 -0
- data/spec/test_suite/negative/20-list_of_objects/errors.json +14 -0
- data/spec/test_suite/negative/20-list_of_objects/input.json +18 -0
- data/spec/test_suite/negative/20-list_of_objects/rules.json +7 -0
- data/spec/test_suite/negative/21-list_of_different_objects/errors.json +17 -0
- data/spec/test_suite/negative/21-list_of_different_objects/input.json +26 -0
- data/spec/test_suite/negative/21-list_of_different_objects/rules.json +17 -0
- data/spec/test_suite/negative/22-not_empty_list/errors.json +7 -0
- data/spec/test_suite/negative/22-not_empty_list/input.json +6 -0
- data/spec/test_suite/negative/22-not_empty_list/rules.json +7 -0
- data/spec/test_suite/negative/23-url/errors.json +10 -0
- data/spec/test_suite/negative/23-url/input.json +12 -0
- data/spec/test_suite/negative/23-url/rules.json +11 -0
- data/spec/test_suite/negative/24-iso_date/errors.json +11 -0
- data/spec/test_suite/negative/24-iso_date/input.json +13 -0
- data/spec/test_suite/negative/24-iso_date/rules.json +12 -0
- data/spec/test_suite/negative/25-eq/errors.json +13 -0
- data/spec/test_suite/negative/25-eq/input.json +14 -0
- data/spec/test_suite/negative/25-eq/rules.json +13 -0
- data/spec/test_suite/negative/26-string/errors.json +6 -0
- data/spec/test_suite/negative/26-string/input.json +6 -0
- data/spec/test_suite/negative/26-string/rules.json +6 -0
- data/spec/test_suite/negative/27-any_object/errors.json +6 -0
- data/spec/test_suite/negative/27-any_object/input.json +6 -0
- data/spec/test_suite/negative/27-any_object/rules.json +6 -0
- data/spec/test_suite/negative/28-variable_object/errors.json +15 -0
- data/spec/test_suite/negative/28-variable_object/input.json +24 -0
- data/spec/test_suite/negative/28-variable_object/rules.json +77 -0
- data/spec/test_suite/negative/29-or/errors.json +14 -0
- data/spec/test_suite/negative/29-or/input.json +20 -0
- data/spec/test_suite/negative/29-or/rules.json +19 -0
- data/spec/test_suite/positive/01-required/input.json +7 -0
- data/spec/test_suite/positive/01-required/output.json +6 -0
- data/spec/test_suite/positive/01-required/rules.json +6 -0
- data/spec/test_suite/positive/02-not_empty/input.json +6 -0
- data/spec/test_suite/positive/02-not_empty/output.json +5 -0
- data/spec/test_suite/positive/02-not_empty/rules.json +6 -0
- data/spec/test_suite/positive/03-one_of/input.json +11 -0
- data/spec/test_suite/positive/03-one_of/output.json +10 -0
- data/spec/test_suite/positive/03-one_of/rules.json +10 -0
- data/spec/test_suite/positive/04-min_length/input.json +8 -0
- data/spec/test_suite/positive/04-min_length/output.json +7 -0
- data/spec/test_suite/positive/04-min_length/rules.json +8 -0
- data/spec/test_suite/positive/05-max_length/input.json +9 -0
- data/spec/test_suite/positive/05-max_length/output.json +8 -0
- data/spec/test_suite/positive/05-max_length/rules.json +9 -0
- data/spec/test_suite/positive/06-length_equal/input.json +8 -0
- data/spec/test_suite/positive/06-length_equal/output.json +7 -0
- data/spec/test_suite/positive/06-length_equal/rules.json +8 -0
- data/spec/test_suite/positive/07-length_between/input.json +9 -0
- data/spec/test_suite/positive/07-length_between/output.json +8 -0
- data/spec/test_suite/positive/07-length_between/rules.json +9 -0
- data/spec/test_suite/positive/08-like/input.json +8 -0
- data/spec/test_suite/positive/08-like/output.json +7 -0
- data/spec/test_suite/positive/08-like/rules.json +8 -0
- data/spec/test_suite/positive/09-integer/input.json +7 -0
- data/spec/test_suite/positive/09-integer/output.json +6 -0
- data/spec/test_suite/positive/09-integer/rules.json +7 -0
- data/spec/test_suite/positive/10-positive_integer/input.json +7 -0
- data/spec/test_suite/positive/10-positive_integer/output.json +6 -0
- data/spec/test_suite/positive/10-positive_integer/rules.json +6 -0
- data/spec/test_suite/positive/11-decimal/input.json +8 -0
- data/spec/test_suite/positive/11-decimal/output.json +7 -0
- data/spec/test_suite/positive/11-decimal/rules.json +7 -0
- data/spec/test_suite/positive/12-positive_decimal/input.json +8 -0
- data/spec/test_suite/positive/12-positive_decimal/output.json +7 -0
- data/spec/test_suite/positive/12-positive_decimal/rules.json +7 -0
- data/spec/test_suite/positive/13-max_number/input.json +7 -0
- data/spec/test_suite/positive/13-max_number/output.json +6 -0
- data/spec/test_suite/positive/13-max_number/rules.json +6 -0
- data/spec/test_suite/positive/14-min_number/input.json +7 -0
- data/spec/test_suite/positive/14-min_number/output.json +6 -0
- data/spec/test_suite/positive/14-min_number/rules.json +6 -0
- data/spec/test_suite/positive/15-number_between/input.json +8 -0
- data/spec/test_suite/positive/15-number_between/output.json +7 -0
- data/spec/test_suite/positive/15-number_between/rules.json +7 -0
- data/spec/test_suite/positive/16-email/input.json +7 -0
- data/spec/test_suite/positive/16-email/output.json +6 -0
- data/spec/test_suite/positive/16-email/rules.json +6 -0
- data/spec/test_suite/positive/17-equal_to_field/input.json +7 -0
- data/spec/test_suite/positive/17-equal_to_field/output.json +6 -0
- data/spec/test_suite/positive/17-equal_to_field/rules.json +6 -0
- data/spec/test_suite/positive/18-nested_object/input.json +15 -0
- data/spec/test_suite/positive/18-nested_object/output.json +12 -0
- data/spec/test_suite/positive/18-nested_object/rules.json +13 -0
- data/spec/test_suite/positive/19-list_of/input.json +7 -0
- data/spec/test_suite/positive/19-list_of/output.json +7 -0
- data/spec/test_suite/positive/19-list_of/rules.json +15 -0
- data/spec/test_suite/positive/20-list_of_objects/input.json +17 -0
- data/spec/test_suite/positive/20-list_of_objects/output.json +17 -0
- data/spec/test_suite/positive/20-list_of_objects/rules.json +10 -0
- data/spec/test_suite/positive/21-list_of_different_objects/input.json +22 -0
- data/spec/test_suite/positive/21-list_of_different_objects/output.json +21 -0
- data/spec/test_suite/positive/21-list_of_different_objects/rules.json +27 -0
- data/spec/test_suite/positive/22-not_empty_list/input.json +6 -0
- data/spec/test_suite/positive/22-not_empty_list/output.json +5 -0
- data/spec/test_suite/positive/22-not_empty_list/rules.json +5 -0
- data/spec/test_suite/positive/23-url/input.json +7 -0
- data/spec/test_suite/positive/23-url/output.json +6 -0
- data/spec/test_suite/positive/23-url/rules.json +6 -0
- data/spec/test_suite/positive/24-iso_date/input.json +9 -0
- data/spec/test_suite/positive/24-iso_date/output.json +8 -0
- data/spec/test_suite/positive/24-iso_date/rules.json +8 -0
- data/spec/test_suite/positive/25-eq/input.json +10 -0
- data/spec/test_suite/positive/25-eq/output.json +9 -0
- data/spec/test_suite/positive/25-eq/rules.json +9 -0
- data/spec/test_suite/positive/26-string/input.json +8 -0
- data/spec/test_suite/positive/26-string/output.json +7 -0
- data/spec/test_suite/positive/26-string/rules.json +7 -0
- data/spec/test_suite/positive/27-any_object/input.json +6 -0
- data/spec/test_suite/positive/27-any_object/output.json +6 -0
- data/spec/test_suite/positive/27-any_object/rules.json +7 -0
- data/spec/test_suite/positive/28-variable_object/input.json +19 -0
- data/spec/test_suite/positive/28-variable_object/output.json +18 -0
- data/spec/test_suite/positive/28-variable_object/rules.json +47 -0
- data/spec/test_suite/positive/29-or/input.json +25 -0
- data/spec/test_suite/positive/29-or/output.json +24 -0
- data/spec/test_suite/positive/29-or/rules.json +24 -0
- data/spec/test_suite/positive/30-trim/input.json +7 -0
- data/spec/test_suite/positive/30-trim/output.json +7 -0
- data/spec/test_suite/positive/30-trim/rules.json +7 -0
- data/spec/test_suite/positive/31-to_lc/input.json +8 -0
- data/spec/test_suite/positive/31-to_lc/output.json +8 -0
- data/spec/test_suite/positive/31-to_lc/rules.json +8 -0
- data/spec/test_suite/positive/32-to_uc/input.json +7 -0
- data/spec/test_suite/positive/32-to_uc/output.json +7 -0
- data/spec/test_suite/positive/32-to_uc/rules.json +7 -0
- data/spec/test_suite/positive/33-remove/input.json +5 -0
- data/spec/test_suite/positive/33-remove/output.json +5 -0
- data/spec/test_suite/positive/33-remove/rules.json +7 -0
- data/spec/test_suite/positive/34-leave_only/input.json +5 -0
- data/spec/test_suite/positive/34-leave_only/output.json +5 -0
- data/spec/test_suite/positive/34-leave_only/rules.json +7 -0
- data/spec/test_suite/positive/35-default/input.json +10 -0
- data/spec/test_suite/positive/35-default/output.json +12 -0
- data/spec/test_suite/positive/35-default/rules.json +12 -0
- metadata +531 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 81c9134b5dc59c32088f0b285b159697bfbbeb1a
|
4
|
+
data.tar.gz: 59b4324bcefda407cbe41a677cc553abe72bafd6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: df65daa6d49b6444826e8e510f912cf7f84519b0fc28699e534b673279ae3f6099656a956ebace58d947bdfa416f5e8b1486f888e92c1cec5781c8a7409b1161
|
7
|
+
data.tar.gz: 7a150d4c4ce0108f60a5285aff998fbb64598c020c354c3cbf62c4fba01219ab3da82e8936466e48d41bdd1b3a955d78afa29f3e6d78c7fb82f62dc82b7e9641
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.ruby-version
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
livr2 (2.0.0)
|
5
|
+
activesupport (~> 5)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (5.1.4)
|
11
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
12
|
+
i18n (~> 0.7)
|
13
|
+
minitest (~> 5.1)
|
14
|
+
tzinfo (~> 1.1)
|
15
|
+
concurrent-ruby (1.0.5)
|
16
|
+
diff-lcs (1.3)
|
17
|
+
i18n (0.9.1)
|
18
|
+
concurrent-ruby (~> 1.0)
|
19
|
+
minitest (5.10.3)
|
20
|
+
rspec (3.7.0)
|
21
|
+
rspec-core (~> 3.7.0)
|
22
|
+
rspec-expectations (~> 3.7.0)
|
23
|
+
rspec-mocks (~> 3.7.0)
|
24
|
+
rspec-core (3.7.0)
|
25
|
+
rspec-support (~> 3.7.0)
|
26
|
+
rspec-expectations (3.7.0)
|
27
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
28
|
+
rspec-support (~> 3.7.0)
|
29
|
+
rspec-mocks (3.7.0)
|
30
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
31
|
+
rspec-support (~> 3.7.0)
|
32
|
+
rspec-support (3.7.0)
|
33
|
+
thread_safe (0.3.6)
|
34
|
+
tzinfo (1.2.4)
|
35
|
+
thread_safe (~> 0.1)
|
36
|
+
|
37
|
+
PLATFORMS
|
38
|
+
ruby
|
39
|
+
|
40
|
+
DEPENDENCIES
|
41
|
+
livr2!
|
42
|
+
rspec (= 3.7)
|
43
|
+
|
44
|
+
BUNDLED WITH
|
45
|
+
1.16.0.pre.3
|
data/Readme.md
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
|
2
|
+
# LIVR Validator
|
3
|
+
LIVR.Validator - Lightweight validator supporting Language Independent Validation Rules Specification (LIVR)
|
4
|
+
|
5
|
+
# SYNOPSIS
|
6
|
+
Common usage:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
gem 'livr2'
|
10
|
+
require 'livr'
|
11
|
+
|
12
|
+
validator = LIVR::Validator.new({
|
13
|
+
'name' => 'required',
|
14
|
+
'email' => [ 'required', 'email' ],
|
15
|
+
'gender' => { 'one_of' => ['male', 'female'] },
|
16
|
+
'phone' => { 'max_length' => 10 },
|
17
|
+
'password' => [ 'required', {min_length : 10} ],
|
18
|
+
'password2' => { 'equal_to_field' => 'password' }
|
19
|
+
});
|
20
|
+
|
21
|
+
valid_data = validator.validate(user_data)
|
22
|
+
|
23
|
+
if (valid_data) {
|
24
|
+
save_user(validData)
|
25
|
+
} else {
|
26
|
+
handle_errors(validator.get_errors)
|
27
|
+
}
|
28
|
+
```
|
29
|
+
|
30
|
+
|
31
|
+
You can use modifiers separately or can combine them with validation:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
var validator = LIVR::Validator.new({
|
35
|
+
email: [ 'required', 'trim', 'email', 'to_lc' ]
|
36
|
+
});
|
37
|
+
```
|
38
|
+
|
39
|
+
|
40
|
+
Feel free to register your own rules:
|
41
|
+
|
42
|
+
You can use aliases(prefferable, syntax covered by the specification) for a lot of cases:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
var validator = LIVR::Validator.new({
|
46
|
+
password: ['required', 'strong_password']
|
47
|
+
});
|
48
|
+
|
49
|
+
validator.register_aliased_rule({
|
50
|
+
name: 'strong_password',
|
51
|
+
rules: {min_length: 6},
|
52
|
+
error: 'WEAK_PASSWORD'
|
53
|
+
});
|
54
|
+
```
|
55
|
+
|
56
|
+
Or you can write more sophisticated rules directly:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
validator = LIVR::Validator.new({
|
60
|
+
password: ['required', 'strong_password']
|
61
|
+
})
|
62
|
+
|
63
|
+
class StrongPassword
|
64
|
+
def call(value, *other_args)
|
65
|
+
# We already have "required" rule to check that the value is present
|
66
|
+
return if value == nil || value == ""
|
67
|
+
if value.length < 6
|
68
|
+
return 'WEAK_PASSWORD'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
# DESCRIPTION
|
75
|
+
This ruby gem is an implementation of LIVR Specification.
|
76
|
+
See ['LIVR Specification'](http://livr-spec.org) for detailed documentation and list of supported rules.
|
77
|
+
|
78
|
+
Features:
|
79
|
+
|
80
|
+
* Rules are declarative and language independent
|
81
|
+
* Any number of rules for each field
|
82
|
+
* Return together errors for all fields
|
83
|
+
* Excludes all fields that do not have validation rules described
|
84
|
+
* Has possibility to validatate complex hierarchical structures
|
85
|
+
* Easy to describe and undersand rules
|
86
|
+
* Returns understandable error codes(not error messages)
|
87
|
+
* Easy to add own rules
|
88
|
+
* Rules are be able to change results output ("trim", "nested\_object", for example)
|
89
|
+
* Multipurpose (user input validation, configs validation, contracts programming etc)
|
90
|
+
|
91
|
+
# INSTALL
|
92
|
+
|
93
|
+
#### as a gem
|
94
|
+
|
95
|
+
```bash
|
96
|
+
gem install livr2
|
97
|
+
```
|
98
|
+
|
99
|
+
#### in rails
|
100
|
+
|
101
|
+
Add to Gemfile
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
gem "livr2"
|
105
|
+
```
|
106
|
+
|
107
|
+
|
108
|
+
# AUTHORS
|
109
|
+
|
110
|
+
## Ruby implementation
|
111
|
+
Vitaliy Yanchuk (@fuksito)
|
112
|
+
|
113
|
+
## Idea and specification
|
114
|
+
Viktor Turskyi (@koorchik)
|
data/lib/livr.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require 'json'
|
3
|
+
require 'date'
|
4
|
+
require 'active_support/all'
|
5
|
+
|
6
|
+
require_relative "livr/validator.rb"
|
7
|
+
require_relative "livr/rule.rb"
|
8
|
+
require_relative "livr/aliased_rule.rb"
|
9
|
+
require_relative "livr/rules/common.rb"
|
10
|
+
require_relative "livr/rules/string.rb"
|
11
|
+
require_relative "livr/rules/numeric.rb"
|
12
|
+
require_relative "livr/rules/special.rb"
|
13
|
+
require_relative "livr/rules/modifiers.rb"
|
14
|
+
require_relative "livr/rules/meta.rb"
|
15
|
+
|
16
|
+
module LIVR
|
17
|
+
DEFAULT_RULES = {
|
18
|
+
required: Rules::Common::Required,
|
19
|
+
not_empty: Rules::Common::NotEmpty,
|
20
|
+
not_empty_list: Rules::Common::NotEmptyList,
|
21
|
+
any_object: Rules::Common::AnyObject,
|
22
|
+
|
23
|
+
string: Rules::String::String,
|
24
|
+
eq: Rules::String::Eq,
|
25
|
+
one_of: Rules::String::OneOf,
|
26
|
+
max_length: Rules::String::MaxLength,
|
27
|
+
min_length: Rules::String::MinLength,
|
28
|
+
length_equal: Rules::String::LengthEqual,
|
29
|
+
length_between: Rules::String::LengthBetween,
|
30
|
+
like: Rules::String::Like,
|
31
|
+
|
32
|
+
integer: Rules::Numeric::Integer,
|
33
|
+
positive_integer: Rules::Numeric::PositiveInteger,
|
34
|
+
decimal: Rules::Numeric::Decimal,
|
35
|
+
positive_decimal: Rules::Numeric::PositiveDecimal,
|
36
|
+
max_number: Rules::Numeric::MaxNumber,
|
37
|
+
min_number: Rules::Numeric::MinNumber,
|
38
|
+
number_between: Rules::Numeric::NumberBetween,
|
39
|
+
|
40
|
+
email: Rules::Special::Email,
|
41
|
+
equal_to_field: Rules::Special::EqualToField,
|
42
|
+
url: Rules::Special::Url,
|
43
|
+
iso_date: Rules::Special::IsoDate,
|
44
|
+
|
45
|
+
default: Rules::Modifiers::Default,
|
46
|
+
trim: Rules::Modifiers::Trim,
|
47
|
+
to_lc: Rules::Modifiers::ToLc,
|
48
|
+
to_uc: Rules::Modifiers::ToUc,
|
49
|
+
remove: Rules::Modifiers::Remove,
|
50
|
+
leave_only: Rules::Modifiers::LeaveOnly,
|
51
|
+
|
52
|
+
nested_object: Rules::Meta::NestedObject,
|
53
|
+
variable_object: Rules::Meta::VariableObject,
|
54
|
+
list_of: Rules::Meta::ListOf,
|
55
|
+
list_of_objects: Rules::Meta::ListOfObjects,
|
56
|
+
list_of_different_objects: Rules::Meta::ListOfDifferentObjects,
|
57
|
+
or: Rules::Meta::Or,
|
58
|
+
}.with_indifferent_access
|
59
|
+
|
60
|
+
Validator.register_default_rules(DEFAULT_RULES)
|
61
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module LIVR
|
2
|
+
class AliasedRule
|
3
|
+
|
4
|
+
def initialize(_alias)
|
5
|
+
raise "Alias name required" unless _alias["name"]
|
6
|
+
raise "Alias rules required" unless _alias["rules"].present?
|
7
|
+
|
8
|
+
@alias = _alias
|
9
|
+
@validator = Validator.new(value: Array.wrap(@alias["rules"]))
|
10
|
+
end
|
11
|
+
|
12
|
+
def new(*args)
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(value, user_data, field_results)
|
17
|
+
result = @validator.validate({ value: value })
|
18
|
+
if result
|
19
|
+
field_results << result[:value]
|
20
|
+
return
|
21
|
+
else
|
22
|
+
return @alias.fetch("error", @validator.get_errors)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/livr/rule.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module LIVR
|
2
|
+
class Rule
|
3
|
+
|
4
|
+
def initialize(*)
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(value, user_data, field_results)
|
8
|
+
raise NotImplementedError
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def is_primitive(value)
|
14
|
+
[Numeric, String, TrueClass, FalseClass].any?{|klass| value.is_a?(klass) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def is_no_value(value)
|
18
|
+
value == nil || value == ""
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module LIVR
|
2
|
+
module Rules
|
3
|
+
module Common
|
4
|
+
|
5
|
+
class Required < Rule
|
6
|
+
def call(value, user_data, field_results)
|
7
|
+
return if value.in?([[], {}])
|
8
|
+
"REQUIRED" if value.blank?
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class NotEmpty < Rule
|
13
|
+
def call(value, user_data, field_results)
|
14
|
+
"CANNOT_BE_EMPTY" if value == ""
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class NotEmptyList < Rule
|
19
|
+
def call(list, user_data, field_results)
|
20
|
+
return "CANNOT_BE_EMPTY" if is_no_value(list)
|
21
|
+
return "CANNOT_BE_EMPTY" if list.is_a?(Array) && list.blank?
|
22
|
+
return "FORMAT_ERROR" unless list.is_a?(Array)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class AnyObject < Rule
|
27
|
+
def call(value, user_data, field_results)
|
28
|
+
return if is_no_value(value)
|
29
|
+
return "FORMAT_ERROR" unless value.is_a?(Hash)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
module LIVR
|
2
|
+
module Rules
|
3
|
+
module Meta
|
4
|
+
|
5
|
+
class NestedObject < Rule
|
6
|
+
def initialize(livr)
|
7
|
+
@validator = Validator.new(livr).prepare
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(nested_object, user_data, field_results)
|
11
|
+
return if is_no_value(nested_object)
|
12
|
+
return 'FORMAT_ERROR' unless nested_object.is_a?(Hash)
|
13
|
+
|
14
|
+
result = @validator.validate(nested_object)
|
15
|
+
|
16
|
+
if result
|
17
|
+
field_results << result
|
18
|
+
return
|
19
|
+
else
|
20
|
+
return @validator.get_errors
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class VariableObject < Rule
|
26
|
+
def initialize(selector_field, livrs)
|
27
|
+
@selector_field = selector_field
|
28
|
+
@validators = {}
|
29
|
+
livrs.each do |selector_value, livr|
|
30
|
+
@validators[selector_value] = Validator.new(livr).prepare
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(object, user_data, field_results)
|
35
|
+
return if is_no_value(object)
|
36
|
+
if ( !object.is_a?(Hash) || !object[@selector_field] || !@validators[ object[@selector_field] ] )
|
37
|
+
return 'FORMAT_ERROR'
|
38
|
+
end
|
39
|
+
|
40
|
+
validator = @validators.fetch(object.fetch(@selector_field))
|
41
|
+
result = validator.validate(object)
|
42
|
+
|
43
|
+
if result
|
44
|
+
field_results << result
|
45
|
+
return
|
46
|
+
else
|
47
|
+
return validator.get_errors
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class ListOf < Rule
|
53
|
+
def initialize(*rules)
|
54
|
+
livr = { field: rules.flatten }
|
55
|
+
@validator = Validator.new(livr).prepare
|
56
|
+
end
|
57
|
+
|
58
|
+
def call(values, user_data, field_results)
|
59
|
+
return if is_no_value(values)
|
60
|
+
return 'FORMAT_ERROR' unless values.is_a?(Array)
|
61
|
+
|
62
|
+
results = []
|
63
|
+
errors = []
|
64
|
+
has_errors = false
|
65
|
+
|
66
|
+
values.each do |value|
|
67
|
+
result = @validator.validate(field: value)
|
68
|
+
|
69
|
+
if result
|
70
|
+
results << result[:field]
|
71
|
+
errors << nil
|
72
|
+
else
|
73
|
+
has_errors = true
|
74
|
+
errors << @validator.get_errors[:field]
|
75
|
+
results << nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
if has_errors
|
80
|
+
return errors
|
81
|
+
else
|
82
|
+
field_results << results
|
83
|
+
return
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class ListOfObjects < Rule
|
89
|
+
def initialize(livr)
|
90
|
+
@validator = Validator.new(livr).prepare
|
91
|
+
end
|
92
|
+
|
93
|
+
def call(objects, user_data, field_results)
|
94
|
+
return if is_no_value(objects)
|
95
|
+
return 'FORMAT_ERROR' unless objects.is_a?(Array)
|
96
|
+
|
97
|
+
results = []
|
98
|
+
errors = []
|
99
|
+
has_errors = false
|
100
|
+
|
101
|
+
objects.each do |object|
|
102
|
+
result = @validator.validate(object)
|
103
|
+
|
104
|
+
if result
|
105
|
+
results << result
|
106
|
+
errors << nil
|
107
|
+
else
|
108
|
+
has_errors = true
|
109
|
+
errors << @validator.get_errors
|
110
|
+
results << nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
if has_errors
|
115
|
+
return errors
|
116
|
+
else
|
117
|
+
field_results << results
|
118
|
+
return
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class ListOfDifferentObjects < Rule
|
125
|
+
def initialize(selector_field, livrs)
|
126
|
+
@selector_field = selector_field
|
127
|
+
@validators = {}
|
128
|
+
livrs.each do |selector_value, livr|
|
129
|
+
@validators[selector_value] = Validator.new(livr).prepare
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def call(objects, user_data, field_results)
|
134
|
+
return if is_no_value(objects)
|
135
|
+
return 'FORMAT_ERROR' unless objects.is_a?(Array)
|
136
|
+
|
137
|
+
results = []
|
138
|
+
errors = []
|
139
|
+
has_errors = false
|
140
|
+
|
141
|
+
objects.each do |object|
|
142
|
+
if !object.is_a?(Hash) || !object[@selector_field] || !@validators[ object[@selector_field] ]
|
143
|
+
errors << 'FORMAT_ERROR'
|
144
|
+
next
|
145
|
+
end
|
146
|
+
|
147
|
+
validator = @validators[ object[@selector_field] ]
|
148
|
+
result = validator.validate(object)
|
149
|
+
|
150
|
+
if result
|
151
|
+
results << result
|
152
|
+
errors << nil
|
153
|
+
else
|
154
|
+
has_errors = true
|
155
|
+
errors << validator.get_errors
|
156
|
+
results << nil
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
if has_errors
|
161
|
+
return errors
|
162
|
+
else
|
163
|
+
field_results << results
|
164
|
+
return
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
class Or < Rule
|
171
|
+
def initialize(*rule_sets)
|
172
|
+
@rule_sets = rule_sets
|
173
|
+
@validators = @rule_sets.map do |rules|
|
174
|
+
livr = { field: rules }
|
175
|
+
Validator.new(livr).prepare
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def call(value, user_data, field_results)
|
180
|
+
return if is_no_value(value)
|
181
|
+
|
182
|
+
last_error = nil
|
183
|
+
@validators.each do |validator|
|
184
|
+
result = validator.validate(field: value)
|
185
|
+
if result
|
186
|
+
field_results << result[:field]
|
187
|
+
return nil
|
188
|
+
else
|
189
|
+
last_error = validator.get_errors[:field]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
last_error ? last_error : nil
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|