livr2 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +45 -0
  6. data/Readme.md +114 -0
  7. data/lib/livr.rb +61 -0
  8. data/lib/livr/aliased_rule.rb +26 -0
  9. data/lib/livr/rule.rb +21 -0
  10. data/lib/livr/rules/common.rb +35 -0
  11. data/lib/livr/rules/meta.rb +200 -0
  12. data/lib/livr/rules/modifiers.rb +68 -0
  13. data/lib/livr/rules/numeric.rb +136 -0
  14. data/lib/livr/rules/special.rb +65 -0
  15. data/lib/livr/rules/string.rb +150 -0
  16. data/lib/livr/validator.rb +137 -0
  17. data/livr2.gemspec +19 -0
  18. data/spec/01-test_suite_spec.rb +34 -0
  19. data/spec/02-aliases_spec.rb +21 -0
  20. data/spec/03-auto_trim_spec.rb +56 -0
  21. data/spec/04-custom_filters_spec.rb +54 -0
  22. data/spec/05-rules_replacement_spec.rb +67 -0
  23. data/spec/spec_helper.rb +3 -0
  24. data/spec/test_suite/aliases_negative/01-adult_age/aliases.json +12 -0
  25. data/spec/test_suite/aliases_negative/01-adult_age/errors.json +6 -0
  26. data/spec/test_suite/aliases_negative/01-adult_age/input.json +11 -0
  27. data/spec/test_suite/aliases_negative/01-adult_age/rules.json +10 -0
  28. data/spec/test_suite/aliases_negative/02-address/aliases.json +20 -0
  29. data/spec/test_suite/aliases_negative/02-address/errors.json +8 -0
  30. data/spec/test_suite/aliases_negative/02-address/input.json +13 -0
  31. data/spec/test_suite/aliases_negative/02-address/rules.json +4 -0
  32. data/spec/test_suite/aliases_negative/03-adult_age_in_user/aliases.json +31 -0
  33. data/spec/test_suite/aliases_negative/03-adult_age_in_user/errors.json +8 -0
  34. data/spec/test_suite/aliases_negative/03-adult_age_in_user/input.json +14 -0
  35. data/spec/test_suite/aliases_negative/03-adult_age_in_user/rules.json +4 -0
  36. data/spec/test_suite/aliases_positive/01-adult_age/aliases.json +12 -0
  37. data/spec/test_suite/aliases_positive/01-adult_age/input.json +11 -0
  38. data/spec/test_suite/aliases_positive/01-adult_age/output.json +10 -0
  39. data/spec/test_suite/aliases_positive/01-adult_age/rules.json +10 -0
  40. data/spec/test_suite/aliases_positive/02-address/aliases.json +20 -0
  41. data/spec/test_suite/aliases_positive/02-address/input.json +13 -0
  42. data/spec/test_suite/aliases_positive/02-address/output.json +12 -0
  43. data/spec/test_suite/aliases_positive/02-address/rules.json +4 -0
  44. data/spec/test_suite/aliases_positive/03-adult_age_in_user/aliases.json +31 -0
  45. data/spec/test_suite/aliases_positive/03-adult_age_in_user/input.json +14 -0
  46. data/spec/test_suite/aliases_positive/03-adult_age_in_user/output.json +12 -0
  47. data/spec/test_suite/aliases_positive/03-adult_age_in_user/rules.json +4 -0
  48. data/spec/test_suite/negative/01-required/errors.json +5 -0
  49. data/spec/test_suite/negative/01-required/input.json +10 -0
  50. data/spec/test_suite/negative/01-required/rules.json +10 -0
  51. data/spec/test_suite/negative/02-not_empty/errors.json +3 -0
  52. data/spec/test_suite/negative/02-not_empty/input.json +10 -0
  53. data/spec/test_suite/negative/02-not_empty/rules.json +10 -0
  54. data/spec/test_suite/negative/03-one_of/errors.json +11 -0
  55. data/spec/test_suite/negative/03-one_of/input.json +12 -0
  56. data/spec/test_suite/negative/03-one_of/rules.json +11 -0
  57. data/spec/test_suite/negative/04-min_length/errors.json +10 -0
  58. data/spec/test_suite/negative/04-min_length/input.json +12 -0
  59. data/spec/test_suite/negative/04-min_length/rules.json +11 -0
  60. data/spec/test_suite/negative/05-max_length/errors.json +10 -0
  61. data/spec/test_suite/negative/05-max_length/input.json +12 -0
  62. data/spec/test_suite/negative/05-max_length/rules.json +11 -0
  63. data/spec/test_suite/negative/06-length_equal/errors.json +10 -0
  64. data/spec/test_suite/negative/06-length_equal/input.json +12 -0
  65. data/spec/test_suite/negative/06-length_equal/rules.json +11 -0
  66. data/spec/test_suite/negative/07-length_between/errors.json +10 -0
  67. data/spec/test_suite/negative/07-length_between/input.json +12 -0
  68. data/spec/test_suite/negative/07-length_between/rules.json +11 -0
  69. data/spec/test_suite/negative/08-like/errors.json +11 -0
  70. data/spec/test_suite/negative/08-like/input.json +14 -0
  71. data/spec/test_suite/negative/08-like/rules.json +12 -0
  72. data/spec/test_suite/negative/09-integer/errors.json +11 -0
  73. data/spec/test_suite/negative/09-integer/input.json +13 -0
  74. data/spec/test_suite/negative/09-integer/rules.json +12 -0
  75. data/spec/test_suite/negative/10-positive_integer/errors.json +11 -0
  76. data/spec/test_suite/negative/10-positive_integer/input.json +13 -0
  77. data/spec/test_suite/negative/10-positive_integer/rules.json +12 -0
  78. data/spec/test_suite/negative/11-decimal/errors.json +11 -0
  79. data/spec/test_suite/negative/11-decimal/input.json +13 -0
  80. data/spec/test_suite/negative/11-decimal/rules.json +12 -0
  81. data/spec/test_suite/negative/12-positive_decimal/errors.json +11 -0
  82. data/spec/test_suite/negative/12-positive_decimal/input.json +13 -0
  83. data/spec/test_suite/negative/12-positive_decimal/rules.json +12 -0
  84. data/spec/test_suite/negative/13-max_number/errors.json +10 -0
  85. data/spec/test_suite/negative/13-max_number/input.json +12 -0
  86. data/spec/test_suite/negative/13-max_number/rules.json +11 -0
  87. data/spec/test_suite/negative/14-min_number/errors.json +11 -0
  88. data/spec/test_suite/negative/14-min_number/input.json +13 -0
  89. data/spec/test_suite/negative/14-min_number/rules.json +12 -0
  90. data/spec/test_suite/negative/15-number_beetween/errors.json +12 -0
  91. data/spec/test_suite/negative/15-number_beetween/input.json +14 -0
  92. data/spec/test_suite/negative/15-number_beetween/rules.json +13 -0
  93. data/spec/test_suite/negative/16-email/errors.json +12 -0
  94. data/spec/test_suite/negative/16-email/input.json +14 -0
  95. data/spec/test_suite/negative/16-email/rules.json +13 -0
  96. data/spec/test_suite/negative/17-equal_to_field/errors.json +10 -0
  97. data/spec/test_suite/negative/17-equal_to_field/input.json +12 -0
  98. data/spec/test_suite/negative/17-equal_to_field/rules.json +11 -0
  99. data/spec/test_suite/negative/18-nested_object/errors.json +9 -0
  100. data/spec/test_suite/negative/18-nested_object/input.json +9 -0
  101. data/spec/test_suite/negative/18-nested_object/rules.json +9 -0
  102. data/spec/test_suite/negative/19-list_of/errors.json +6 -0
  103. data/spec/test_suite/negative/19-list_of/input.json +6 -0
  104. data/spec/test_suite/negative/19-list_of/rules.json +14 -0
  105. data/spec/test_suite/negative/20-list_of_objects/errors.json +14 -0
  106. data/spec/test_suite/negative/20-list_of_objects/input.json +18 -0
  107. data/spec/test_suite/negative/20-list_of_objects/rules.json +7 -0
  108. data/spec/test_suite/negative/21-list_of_different_objects/errors.json +17 -0
  109. data/spec/test_suite/negative/21-list_of_different_objects/input.json +26 -0
  110. data/spec/test_suite/negative/21-list_of_different_objects/rules.json +17 -0
  111. data/spec/test_suite/negative/22-not_empty_list/errors.json +7 -0
  112. data/spec/test_suite/negative/22-not_empty_list/input.json +6 -0
  113. data/spec/test_suite/negative/22-not_empty_list/rules.json +7 -0
  114. data/spec/test_suite/negative/23-url/errors.json +10 -0
  115. data/spec/test_suite/negative/23-url/input.json +12 -0
  116. data/spec/test_suite/negative/23-url/rules.json +11 -0
  117. data/spec/test_suite/negative/24-iso_date/errors.json +11 -0
  118. data/spec/test_suite/negative/24-iso_date/input.json +13 -0
  119. data/spec/test_suite/negative/24-iso_date/rules.json +12 -0
  120. data/spec/test_suite/negative/25-eq/errors.json +13 -0
  121. data/spec/test_suite/negative/25-eq/input.json +14 -0
  122. data/spec/test_suite/negative/25-eq/rules.json +13 -0
  123. data/spec/test_suite/negative/26-string/errors.json +6 -0
  124. data/spec/test_suite/negative/26-string/input.json +6 -0
  125. data/spec/test_suite/negative/26-string/rules.json +6 -0
  126. data/spec/test_suite/negative/27-any_object/errors.json +6 -0
  127. data/spec/test_suite/negative/27-any_object/input.json +6 -0
  128. data/spec/test_suite/negative/27-any_object/rules.json +6 -0
  129. data/spec/test_suite/negative/28-variable_object/errors.json +15 -0
  130. data/spec/test_suite/negative/28-variable_object/input.json +24 -0
  131. data/spec/test_suite/negative/28-variable_object/rules.json +77 -0
  132. data/spec/test_suite/negative/29-or/errors.json +14 -0
  133. data/spec/test_suite/negative/29-or/input.json +20 -0
  134. data/spec/test_suite/negative/29-or/rules.json +19 -0
  135. data/spec/test_suite/positive/01-required/input.json +7 -0
  136. data/spec/test_suite/positive/01-required/output.json +6 -0
  137. data/spec/test_suite/positive/01-required/rules.json +6 -0
  138. data/spec/test_suite/positive/02-not_empty/input.json +6 -0
  139. data/spec/test_suite/positive/02-not_empty/output.json +5 -0
  140. data/spec/test_suite/positive/02-not_empty/rules.json +6 -0
  141. data/spec/test_suite/positive/03-one_of/input.json +11 -0
  142. data/spec/test_suite/positive/03-one_of/output.json +10 -0
  143. data/spec/test_suite/positive/03-one_of/rules.json +10 -0
  144. data/spec/test_suite/positive/04-min_length/input.json +8 -0
  145. data/spec/test_suite/positive/04-min_length/output.json +7 -0
  146. data/spec/test_suite/positive/04-min_length/rules.json +8 -0
  147. data/spec/test_suite/positive/05-max_length/input.json +9 -0
  148. data/spec/test_suite/positive/05-max_length/output.json +8 -0
  149. data/spec/test_suite/positive/05-max_length/rules.json +9 -0
  150. data/spec/test_suite/positive/06-length_equal/input.json +8 -0
  151. data/spec/test_suite/positive/06-length_equal/output.json +7 -0
  152. data/spec/test_suite/positive/06-length_equal/rules.json +8 -0
  153. data/spec/test_suite/positive/07-length_between/input.json +9 -0
  154. data/spec/test_suite/positive/07-length_between/output.json +8 -0
  155. data/spec/test_suite/positive/07-length_between/rules.json +9 -0
  156. data/spec/test_suite/positive/08-like/input.json +8 -0
  157. data/spec/test_suite/positive/08-like/output.json +7 -0
  158. data/spec/test_suite/positive/08-like/rules.json +8 -0
  159. data/spec/test_suite/positive/09-integer/input.json +7 -0
  160. data/spec/test_suite/positive/09-integer/output.json +6 -0
  161. data/spec/test_suite/positive/09-integer/rules.json +7 -0
  162. data/spec/test_suite/positive/10-positive_integer/input.json +7 -0
  163. data/spec/test_suite/positive/10-positive_integer/output.json +6 -0
  164. data/spec/test_suite/positive/10-positive_integer/rules.json +6 -0
  165. data/spec/test_suite/positive/11-decimal/input.json +8 -0
  166. data/spec/test_suite/positive/11-decimal/output.json +7 -0
  167. data/spec/test_suite/positive/11-decimal/rules.json +7 -0
  168. data/spec/test_suite/positive/12-positive_decimal/input.json +8 -0
  169. data/spec/test_suite/positive/12-positive_decimal/output.json +7 -0
  170. data/spec/test_suite/positive/12-positive_decimal/rules.json +7 -0
  171. data/spec/test_suite/positive/13-max_number/input.json +7 -0
  172. data/spec/test_suite/positive/13-max_number/output.json +6 -0
  173. data/spec/test_suite/positive/13-max_number/rules.json +6 -0
  174. data/spec/test_suite/positive/14-min_number/input.json +7 -0
  175. data/spec/test_suite/positive/14-min_number/output.json +6 -0
  176. data/spec/test_suite/positive/14-min_number/rules.json +6 -0
  177. data/spec/test_suite/positive/15-number_between/input.json +8 -0
  178. data/spec/test_suite/positive/15-number_between/output.json +7 -0
  179. data/spec/test_suite/positive/15-number_between/rules.json +7 -0
  180. data/spec/test_suite/positive/16-email/input.json +7 -0
  181. data/spec/test_suite/positive/16-email/output.json +6 -0
  182. data/spec/test_suite/positive/16-email/rules.json +6 -0
  183. data/spec/test_suite/positive/17-equal_to_field/input.json +7 -0
  184. data/spec/test_suite/positive/17-equal_to_field/output.json +6 -0
  185. data/spec/test_suite/positive/17-equal_to_field/rules.json +6 -0
  186. data/spec/test_suite/positive/18-nested_object/input.json +15 -0
  187. data/spec/test_suite/positive/18-nested_object/output.json +12 -0
  188. data/spec/test_suite/positive/18-nested_object/rules.json +13 -0
  189. data/spec/test_suite/positive/19-list_of/input.json +7 -0
  190. data/spec/test_suite/positive/19-list_of/output.json +7 -0
  191. data/spec/test_suite/positive/19-list_of/rules.json +15 -0
  192. data/spec/test_suite/positive/20-list_of_objects/input.json +17 -0
  193. data/spec/test_suite/positive/20-list_of_objects/output.json +17 -0
  194. data/spec/test_suite/positive/20-list_of_objects/rules.json +10 -0
  195. data/spec/test_suite/positive/21-list_of_different_objects/input.json +22 -0
  196. data/spec/test_suite/positive/21-list_of_different_objects/output.json +21 -0
  197. data/spec/test_suite/positive/21-list_of_different_objects/rules.json +27 -0
  198. data/spec/test_suite/positive/22-not_empty_list/input.json +6 -0
  199. data/spec/test_suite/positive/22-not_empty_list/output.json +5 -0
  200. data/spec/test_suite/positive/22-not_empty_list/rules.json +5 -0
  201. data/spec/test_suite/positive/23-url/input.json +7 -0
  202. data/spec/test_suite/positive/23-url/output.json +6 -0
  203. data/spec/test_suite/positive/23-url/rules.json +6 -0
  204. data/spec/test_suite/positive/24-iso_date/input.json +9 -0
  205. data/spec/test_suite/positive/24-iso_date/output.json +8 -0
  206. data/spec/test_suite/positive/24-iso_date/rules.json +8 -0
  207. data/spec/test_suite/positive/25-eq/input.json +10 -0
  208. data/spec/test_suite/positive/25-eq/output.json +9 -0
  209. data/spec/test_suite/positive/25-eq/rules.json +9 -0
  210. data/spec/test_suite/positive/26-string/input.json +8 -0
  211. data/spec/test_suite/positive/26-string/output.json +7 -0
  212. data/spec/test_suite/positive/26-string/rules.json +7 -0
  213. data/spec/test_suite/positive/27-any_object/input.json +6 -0
  214. data/spec/test_suite/positive/27-any_object/output.json +6 -0
  215. data/spec/test_suite/positive/27-any_object/rules.json +7 -0
  216. data/spec/test_suite/positive/28-variable_object/input.json +19 -0
  217. data/spec/test_suite/positive/28-variable_object/output.json +18 -0
  218. data/spec/test_suite/positive/28-variable_object/rules.json +47 -0
  219. data/spec/test_suite/positive/29-or/input.json +25 -0
  220. data/spec/test_suite/positive/29-or/output.json +24 -0
  221. data/spec/test_suite/positive/29-or/rules.json +24 -0
  222. data/spec/test_suite/positive/30-trim/input.json +7 -0
  223. data/spec/test_suite/positive/30-trim/output.json +7 -0
  224. data/spec/test_suite/positive/30-trim/rules.json +7 -0
  225. data/spec/test_suite/positive/31-to_lc/input.json +8 -0
  226. data/spec/test_suite/positive/31-to_lc/output.json +8 -0
  227. data/spec/test_suite/positive/31-to_lc/rules.json +8 -0
  228. data/spec/test_suite/positive/32-to_uc/input.json +7 -0
  229. data/spec/test_suite/positive/32-to_uc/output.json +7 -0
  230. data/spec/test_suite/positive/32-to_uc/rules.json +7 -0
  231. data/spec/test_suite/positive/33-remove/input.json +5 -0
  232. data/spec/test_suite/positive/33-remove/output.json +5 -0
  233. data/spec/test_suite/positive/33-remove/rules.json +7 -0
  234. data/spec/test_suite/positive/34-leave_only/input.json +5 -0
  235. data/spec/test_suite/positive/34-leave_only/output.json +5 -0
  236. data/spec/test_suite/positive/34-leave_only/rules.json +7 -0
  237. data/spec/test_suite/positive/35-default/input.json +10 -0
  238. data/spec/test_suite/positive/35-default/output.json +12 -0
  239. data/spec/test_suite/positive/35-default/rules.json +12 -0
  240. metadata +531 -0
@@ -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
@@ -0,0 +1 @@
1
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color spec
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
@@ -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
@@ -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)
@@ -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
@@ -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
+