ruby-livr 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (241) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile.lock +45 -0
  7. data/Readme.md +119 -0
  8. data/lib/livr.rb +60 -0
  9. data/lib/livr/aliased_rule.rb +26 -0
  10. data/lib/livr/rule.rb +21 -0
  11. data/lib/livr/rules/common.rb +35 -0
  12. data/lib/livr/rules/meta.rb +200 -0
  13. data/lib/livr/rules/modifiers.rb +68 -0
  14. data/lib/livr/rules/numeric.rb +136 -0
  15. data/lib/livr/rules/special.rb +65 -0
  16. data/lib/livr/rules/string.rb +150 -0
  17. data/lib/livr/validator.rb +134 -0
  18. data/ruby-livr.gemspec +19 -0
  19. data/spec/01-test_suite_spec.rb +34 -0
  20. data/spec/02-aliases_spec.rb +21 -0
  21. data/spec/03-auto_trim_spec.rb +56 -0
  22. data/spec/04-custom_filters_spec.rb +54 -0
  23. data/spec/05-rules_replacement_spec.rb +67 -0
  24. data/spec/spec_helper.rb +3 -0
  25. data/spec/test_suite/aliases_negative/01-adult_age/aliases.json +12 -0
  26. data/spec/test_suite/aliases_negative/01-adult_age/errors.json +6 -0
  27. data/spec/test_suite/aliases_negative/01-adult_age/input.json +11 -0
  28. data/spec/test_suite/aliases_negative/01-adult_age/rules.json +10 -0
  29. data/spec/test_suite/aliases_negative/02-address/aliases.json +20 -0
  30. data/spec/test_suite/aliases_negative/02-address/errors.json +8 -0
  31. data/spec/test_suite/aliases_negative/02-address/input.json +13 -0
  32. data/spec/test_suite/aliases_negative/02-address/rules.json +4 -0
  33. data/spec/test_suite/aliases_negative/03-adult_age_in_user/aliases.json +31 -0
  34. data/spec/test_suite/aliases_negative/03-adult_age_in_user/errors.json +8 -0
  35. data/spec/test_suite/aliases_negative/03-adult_age_in_user/input.json +14 -0
  36. data/spec/test_suite/aliases_negative/03-adult_age_in_user/rules.json +4 -0
  37. data/spec/test_suite/aliases_positive/01-adult_age/aliases.json +12 -0
  38. data/spec/test_suite/aliases_positive/01-adult_age/input.json +11 -0
  39. data/spec/test_suite/aliases_positive/01-adult_age/output.json +10 -0
  40. data/spec/test_suite/aliases_positive/01-adult_age/rules.json +10 -0
  41. data/spec/test_suite/aliases_positive/02-address/aliases.json +20 -0
  42. data/spec/test_suite/aliases_positive/02-address/input.json +13 -0
  43. data/spec/test_suite/aliases_positive/02-address/output.json +12 -0
  44. data/spec/test_suite/aliases_positive/02-address/rules.json +4 -0
  45. data/spec/test_suite/aliases_positive/03-adult_age_in_user/aliases.json +31 -0
  46. data/spec/test_suite/aliases_positive/03-adult_age_in_user/input.json +14 -0
  47. data/spec/test_suite/aliases_positive/03-adult_age_in_user/output.json +12 -0
  48. data/spec/test_suite/aliases_positive/03-adult_age_in_user/rules.json +4 -0
  49. data/spec/test_suite/negative/01-required/errors.json +5 -0
  50. data/spec/test_suite/negative/01-required/input.json +10 -0
  51. data/spec/test_suite/negative/01-required/rules.json +10 -0
  52. data/spec/test_suite/negative/02-not_empty/errors.json +3 -0
  53. data/spec/test_suite/negative/02-not_empty/input.json +10 -0
  54. data/spec/test_suite/negative/02-not_empty/rules.json +10 -0
  55. data/spec/test_suite/negative/03-one_of/errors.json +11 -0
  56. data/spec/test_suite/negative/03-one_of/input.json +12 -0
  57. data/spec/test_suite/negative/03-one_of/rules.json +11 -0
  58. data/spec/test_suite/negative/04-min_length/errors.json +10 -0
  59. data/spec/test_suite/negative/04-min_length/input.json +12 -0
  60. data/spec/test_suite/negative/04-min_length/rules.json +11 -0
  61. data/spec/test_suite/negative/05-max_length/errors.json +10 -0
  62. data/spec/test_suite/negative/05-max_length/input.json +12 -0
  63. data/spec/test_suite/negative/05-max_length/rules.json +11 -0
  64. data/spec/test_suite/negative/06-length_equal/errors.json +10 -0
  65. data/spec/test_suite/negative/06-length_equal/input.json +12 -0
  66. data/spec/test_suite/negative/06-length_equal/rules.json +11 -0
  67. data/spec/test_suite/negative/07-length_between/errors.json +10 -0
  68. data/spec/test_suite/negative/07-length_between/input.json +12 -0
  69. data/spec/test_suite/negative/07-length_between/rules.json +11 -0
  70. data/spec/test_suite/negative/08-like/errors.json +11 -0
  71. data/spec/test_suite/negative/08-like/input.json +14 -0
  72. data/spec/test_suite/negative/08-like/rules.json +12 -0
  73. data/spec/test_suite/negative/09-integer/errors.json +11 -0
  74. data/spec/test_suite/negative/09-integer/input.json +13 -0
  75. data/spec/test_suite/negative/09-integer/rules.json +12 -0
  76. data/spec/test_suite/negative/10-positive_integer/errors.json +11 -0
  77. data/spec/test_suite/negative/10-positive_integer/input.json +13 -0
  78. data/spec/test_suite/negative/10-positive_integer/rules.json +12 -0
  79. data/spec/test_suite/negative/11-decimal/errors.json +11 -0
  80. data/spec/test_suite/negative/11-decimal/input.json +13 -0
  81. data/spec/test_suite/negative/11-decimal/rules.json +12 -0
  82. data/spec/test_suite/negative/12-positive_decimal/errors.json +11 -0
  83. data/spec/test_suite/negative/12-positive_decimal/input.json +13 -0
  84. data/spec/test_suite/negative/12-positive_decimal/rules.json +12 -0
  85. data/spec/test_suite/negative/13-max_number/errors.json +10 -0
  86. data/spec/test_suite/negative/13-max_number/input.json +12 -0
  87. data/spec/test_suite/negative/13-max_number/rules.json +11 -0
  88. data/spec/test_suite/negative/14-min_number/errors.json +11 -0
  89. data/spec/test_suite/negative/14-min_number/input.json +13 -0
  90. data/spec/test_suite/negative/14-min_number/rules.json +12 -0
  91. data/spec/test_suite/negative/15-number_beetween/errors.json +12 -0
  92. data/spec/test_suite/negative/15-number_beetween/input.json +14 -0
  93. data/spec/test_suite/negative/15-number_beetween/rules.json +13 -0
  94. data/spec/test_suite/negative/16-email/errors.json +12 -0
  95. data/spec/test_suite/negative/16-email/input.json +14 -0
  96. data/spec/test_suite/negative/16-email/rules.json +13 -0
  97. data/spec/test_suite/negative/17-equal_to_field/errors.json +10 -0
  98. data/spec/test_suite/negative/17-equal_to_field/input.json +12 -0
  99. data/spec/test_suite/negative/17-equal_to_field/rules.json +11 -0
  100. data/spec/test_suite/negative/18-nested_object/errors.json +9 -0
  101. data/spec/test_suite/negative/18-nested_object/input.json +9 -0
  102. data/spec/test_suite/negative/18-nested_object/rules.json +9 -0
  103. data/spec/test_suite/negative/19-list_of/errors.json +6 -0
  104. data/spec/test_suite/negative/19-list_of/input.json +6 -0
  105. data/spec/test_suite/negative/19-list_of/rules.json +14 -0
  106. data/spec/test_suite/negative/20-list_of_objects/errors.json +14 -0
  107. data/spec/test_suite/negative/20-list_of_objects/input.json +18 -0
  108. data/spec/test_suite/negative/20-list_of_objects/rules.json +7 -0
  109. data/spec/test_suite/negative/21-list_of_different_objects/errors.json +17 -0
  110. data/spec/test_suite/negative/21-list_of_different_objects/input.json +26 -0
  111. data/spec/test_suite/negative/21-list_of_different_objects/rules.json +17 -0
  112. data/spec/test_suite/negative/22-not_empty_list/errors.json +7 -0
  113. data/spec/test_suite/negative/22-not_empty_list/input.json +6 -0
  114. data/spec/test_suite/negative/22-not_empty_list/rules.json +7 -0
  115. data/spec/test_suite/negative/23-url/errors.json +10 -0
  116. data/spec/test_suite/negative/23-url/input.json +12 -0
  117. data/spec/test_suite/negative/23-url/rules.json +11 -0
  118. data/spec/test_suite/negative/24-iso_date/errors.json +11 -0
  119. data/spec/test_suite/negative/24-iso_date/input.json +13 -0
  120. data/spec/test_suite/negative/24-iso_date/rules.json +12 -0
  121. data/spec/test_suite/negative/25-eq/errors.json +13 -0
  122. data/spec/test_suite/negative/25-eq/input.json +14 -0
  123. data/spec/test_suite/negative/25-eq/rules.json +13 -0
  124. data/spec/test_suite/negative/26-string/errors.json +6 -0
  125. data/spec/test_suite/negative/26-string/input.json +6 -0
  126. data/spec/test_suite/negative/26-string/rules.json +6 -0
  127. data/spec/test_suite/negative/27-any_object/errors.json +6 -0
  128. data/spec/test_suite/negative/27-any_object/input.json +6 -0
  129. data/spec/test_suite/negative/27-any_object/rules.json +6 -0
  130. data/spec/test_suite/negative/28-variable_object/errors.json +15 -0
  131. data/spec/test_suite/negative/28-variable_object/input.json +24 -0
  132. data/spec/test_suite/negative/28-variable_object/rules.json +77 -0
  133. data/spec/test_suite/negative/29-or/errors.json +14 -0
  134. data/spec/test_suite/negative/29-or/input.json +20 -0
  135. data/spec/test_suite/negative/29-or/rules.json +19 -0
  136. data/spec/test_suite/positive/01-required/input.json +7 -0
  137. data/spec/test_suite/positive/01-required/output.json +6 -0
  138. data/spec/test_suite/positive/01-required/rules.json +6 -0
  139. data/spec/test_suite/positive/02-not_empty/input.json +6 -0
  140. data/spec/test_suite/positive/02-not_empty/output.json +5 -0
  141. data/spec/test_suite/positive/02-not_empty/rules.json +6 -0
  142. data/spec/test_suite/positive/03-one_of/input.json +11 -0
  143. data/spec/test_suite/positive/03-one_of/output.json +10 -0
  144. data/spec/test_suite/positive/03-one_of/rules.json +10 -0
  145. data/spec/test_suite/positive/04-min_length/input.json +8 -0
  146. data/spec/test_suite/positive/04-min_length/output.json +7 -0
  147. data/spec/test_suite/positive/04-min_length/rules.json +8 -0
  148. data/spec/test_suite/positive/05-max_length/input.json +9 -0
  149. data/spec/test_suite/positive/05-max_length/output.json +8 -0
  150. data/spec/test_suite/positive/05-max_length/rules.json +9 -0
  151. data/spec/test_suite/positive/06-length_equal/input.json +8 -0
  152. data/spec/test_suite/positive/06-length_equal/output.json +7 -0
  153. data/spec/test_suite/positive/06-length_equal/rules.json +8 -0
  154. data/spec/test_suite/positive/07-length_between/input.json +9 -0
  155. data/spec/test_suite/positive/07-length_between/output.json +8 -0
  156. data/spec/test_suite/positive/07-length_between/rules.json +9 -0
  157. data/spec/test_suite/positive/08-like/input.json +8 -0
  158. data/spec/test_suite/positive/08-like/output.json +7 -0
  159. data/spec/test_suite/positive/08-like/rules.json +8 -0
  160. data/spec/test_suite/positive/09-integer/input.json +7 -0
  161. data/spec/test_suite/positive/09-integer/output.json +6 -0
  162. data/spec/test_suite/positive/09-integer/rules.json +7 -0
  163. data/spec/test_suite/positive/10-positive_integer/input.json +7 -0
  164. data/spec/test_suite/positive/10-positive_integer/output.json +6 -0
  165. data/spec/test_suite/positive/10-positive_integer/rules.json +6 -0
  166. data/spec/test_suite/positive/11-decimal/input.json +8 -0
  167. data/spec/test_suite/positive/11-decimal/output.json +7 -0
  168. data/spec/test_suite/positive/11-decimal/rules.json +7 -0
  169. data/spec/test_suite/positive/12-positive_decimal/input.json +8 -0
  170. data/spec/test_suite/positive/12-positive_decimal/output.json +7 -0
  171. data/spec/test_suite/positive/12-positive_decimal/rules.json +7 -0
  172. data/spec/test_suite/positive/13-max_number/input.json +7 -0
  173. data/spec/test_suite/positive/13-max_number/output.json +6 -0
  174. data/spec/test_suite/positive/13-max_number/rules.json +6 -0
  175. data/spec/test_suite/positive/14-min_number/input.json +7 -0
  176. data/spec/test_suite/positive/14-min_number/output.json +6 -0
  177. data/spec/test_suite/positive/14-min_number/rules.json +6 -0
  178. data/spec/test_suite/positive/15-number_between/input.json +8 -0
  179. data/spec/test_suite/positive/15-number_between/output.json +7 -0
  180. data/spec/test_suite/positive/15-number_between/rules.json +7 -0
  181. data/spec/test_suite/positive/16-email/input.json +7 -0
  182. data/spec/test_suite/positive/16-email/output.json +6 -0
  183. data/spec/test_suite/positive/16-email/rules.json +6 -0
  184. data/spec/test_suite/positive/17-equal_to_field/input.json +7 -0
  185. data/spec/test_suite/positive/17-equal_to_field/output.json +6 -0
  186. data/spec/test_suite/positive/17-equal_to_field/rules.json +6 -0
  187. data/spec/test_suite/positive/18-nested_object/input.json +15 -0
  188. data/spec/test_suite/positive/18-nested_object/output.json +12 -0
  189. data/spec/test_suite/positive/18-nested_object/rules.json +13 -0
  190. data/spec/test_suite/positive/19-list_of/input.json +7 -0
  191. data/spec/test_suite/positive/19-list_of/output.json +7 -0
  192. data/spec/test_suite/positive/19-list_of/rules.json +15 -0
  193. data/spec/test_suite/positive/20-list_of_objects/input.json +17 -0
  194. data/spec/test_suite/positive/20-list_of_objects/output.json +17 -0
  195. data/spec/test_suite/positive/20-list_of_objects/rules.json +10 -0
  196. data/spec/test_suite/positive/21-list_of_different_objects/input.json +22 -0
  197. data/spec/test_suite/positive/21-list_of_different_objects/output.json +21 -0
  198. data/spec/test_suite/positive/21-list_of_different_objects/rules.json +27 -0
  199. data/spec/test_suite/positive/22-not_empty_list/input.json +6 -0
  200. data/spec/test_suite/positive/22-not_empty_list/output.json +5 -0
  201. data/spec/test_suite/positive/22-not_empty_list/rules.json +5 -0
  202. data/spec/test_suite/positive/23-url/input.json +7 -0
  203. data/spec/test_suite/positive/23-url/output.json +6 -0
  204. data/spec/test_suite/positive/23-url/rules.json +6 -0
  205. data/spec/test_suite/positive/24-iso_date/input.json +9 -0
  206. data/spec/test_suite/positive/24-iso_date/output.json +8 -0
  207. data/spec/test_suite/positive/24-iso_date/rules.json +8 -0
  208. data/spec/test_suite/positive/25-eq/input.json +10 -0
  209. data/spec/test_suite/positive/25-eq/output.json +9 -0
  210. data/spec/test_suite/positive/25-eq/rules.json +9 -0
  211. data/spec/test_suite/positive/26-string/input.json +8 -0
  212. data/spec/test_suite/positive/26-string/output.json +7 -0
  213. data/spec/test_suite/positive/26-string/rules.json +7 -0
  214. data/spec/test_suite/positive/27-any_object/input.json +6 -0
  215. data/spec/test_suite/positive/27-any_object/output.json +6 -0
  216. data/spec/test_suite/positive/27-any_object/rules.json +7 -0
  217. data/spec/test_suite/positive/28-variable_object/input.json +19 -0
  218. data/spec/test_suite/positive/28-variable_object/output.json +18 -0
  219. data/spec/test_suite/positive/28-variable_object/rules.json +47 -0
  220. data/spec/test_suite/positive/29-or/input.json +25 -0
  221. data/spec/test_suite/positive/29-or/output.json +24 -0
  222. data/spec/test_suite/positive/29-or/rules.json +24 -0
  223. data/spec/test_suite/positive/30-trim/input.json +7 -0
  224. data/spec/test_suite/positive/30-trim/output.json +7 -0
  225. data/spec/test_suite/positive/30-trim/rules.json +7 -0
  226. data/spec/test_suite/positive/31-to_lc/input.json +8 -0
  227. data/spec/test_suite/positive/31-to_lc/output.json +8 -0
  228. data/spec/test_suite/positive/31-to_lc/rules.json +8 -0
  229. data/spec/test_suite/positive/32-to_uc/input.json +7 -0
  230. data/spec/test_suite/positive/32-to_uc/output.json +7 -0
  231. data/spec/test_suite/positive/32-to_uc/rules.json +7 -0
  232. data/spec/test_suite/positive/33-remove/input.json +5 -0
  233. data/spec/test_suite/positive/33-remove/output.json +5 -0
  234. data/spec/test_suite/positive/33-remove/rules.json +7 -0
  235. data/spec/test_suite/positive/34-leave_only/input.json +5 -0
  236. data/spec/test_suite/positive/34-leave_only/output.json +5 -0
  237. data/spec/test_suite/positive/34-leave_only/rules.json +7 -0
  238. data/spec/test_suite/positive/35-default/input.json +10 -0
  239. data/spec/test_suite/positive/35-default/output.json +12 -0
  240. data/spec/test_suite/positive/35-default/rules.json +12 -0
  241. metadata +532 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 43a065b27ff89d4be35e4ee14ced13cf49da7cba
4
+ data.tar.gz: c92bd4fab2be4a2d5439446de2a1a17830414a10
5
+ SHA512:
6
+ metadata.gz: be28f102a0c2e5f1448496904264d1837bc591c4070bf2cf505368397c3433debfa58c9c6ef904ce783193ad4ed333056a822c7e53d9933997cb6e2098234989
7
+ data.tar.gz: 715d4b10d9282d7c80a78cc4eb5bcca8f9a43812258de02f3f7e427ee373f08cfc68c03fe7e823a122a0c50ba898d81614bfb8021c75d8cfbbd109c1c99862ff
@@ -0,0 +1,2 @@
1
+ .ruby-version
2
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color spec
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ script: bundle exec rspec
3
+ rvm:
4
+ - 2.2
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
+ ruby-livr (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
+ rspec (= 3.7)
42
+ ruby-livr!
43
+
44
+ BUNDLED WITH
45
+ 1.16.0.pre.3
@@ -0,0 +1,119 @@
1
+ [![Build Status](https://travis-ci.org/fuksito/ruby-livr.svg?branch=master)](https://travis-ci.org/fuksito/ruby-livr)
2
+
3
+ # LIVR Validator
4
+ LIVR.Validator - Lightweight validator supporting Language Independent Validation Rules Specification (LIVR)
5
+ Implements latest ['2.0 specification'](http://livr-spec.org)
6
+
7
+ # SYNOPSIS
8
+ Common usage:
9
+
10
+ ```ruby
11
+ gem 'ruby-livr'
12
+ require 'livr'
13
+
14
+ validator = LIVR::Validator.new({
15
+ 'name' => 'required',
16
+ 'email' => [ 'required', 'email' ],
17
+ 'gender' => { 'one_of' => ['male', 'female'] },
18
+ 'phone' => { 'max_length' => 10 },
19
+ 'password' => [ 'required', { 'min_length' => 10} ],
20
+ 'password2' => { 'equal_to_field' => 'password' }
21
+ });
22
+
23
+ valid_data = validator.validate(user_data)
24
+
25
+ if valid_data
26
+ save_user(validData)
27
+ else
28
+ handle_errors(validator.get_errors)
29
+ end
30
+ ```
31
+
32
+
33
+ You can use modifiers separately or can combine them with validation:
34
+
35
+ ```ruby
36
+ validator = LIVR::Validator.new({
37
+ 'email' => [ 'required', 'trim', 'email', 'to_lc' ]
38
+ });
39
+ ```
40
+
41
+
42
+ Feel free to register your own rules:
43
+
44
+ You can use aliases(prefferable, syntax covered by the specification) for a lot of cases:
45
+
46
+ ```ruby
47
+ validator = LIVR::Validator.new({
48
+ 'password' => ['required', 'strong_password']
49
+ });
50
+
51
+ validator.register_aliased_rule({
52
+ 'name' => 'strong_password',
53
+ 'rules' => { 'min_length' => 6},
54
+ 'error' => 'WEAK_PASSWORD'
55
+ });
56
+ ```
57
+
58
+ Or you can write more sophisticated rules directly:
59
+
60
+ ```ruby
61
+ validator = LIVR::Validator.new({
62
+ 'password' => ['required', 'strong_password']
63
+ })
64
+
65
+ class StrongPassword
66
+ def call(value, *other_args)
67
+ # We already have "required" rule to check that the value is present
68
+ return if value == nil || value == ""
69
+ if value.length < 6
70
+ return 'WEAK_PASSWORD'
71
+ end
72
+ end
73
+ end
74
+
75
+ validator.register_rules(strong_password: StrongPassword)
76
+
77
+ ```
78
+
79
+ # DESCRIPTION
80
+ This ruby gem is an implementation of LIVR Specification.
81
+ See ['LIVR Specification'](http://livr-spec.org) for detailed documentation and list of supported rules.
82
+
83
+ Features:
84
+
85
+ * Rules are declarative and language independent
86
+ * Any number of rules for each field
87
+ * Return together errors for all fields
88
+ * Excludes all fields that do not have validation rules described
89
+ * Has possibility to validatate complex hierarchical structures
90
+ * Easy to describe and undersand rules
91
+ * Returns understandable error codes(not error messages)
92
+ * Easy to add own rules
93
+ * Rules are be able to change results output ("trim", "nested\_object", for example)
94
+ * Multipurpose (user input validation, configs validation, contracts programming etc)
95
+
96
+ # INSTALL
97
+
98
+ #### as a gem
99
+
100
+ ```bash
101
+ gem install ruby-livr
102
+ ```
103
+
104
+ #### in rails
105
+
106
+ Add to Gemfile
107
+
108
+ ```ruby
109
+ gem "ruby-livr"
110
+ ```
111
+
112
+
113
+ # AUTHORS
114
+
115
+ ## Ruby implementation
116
+ Vitaliy Yanchuk (@fuksito)
117
+
118
+ ## Idea and specification
119
+ Viktor Turskyi (@koorchik)
@@ -0,0 +1,60 @@
1
+ require 'json'
2
+ require 'date'
3
+ require 'active_support/all'
4
+
5
+ require_relative "livr/validator.rb"
6
+ require_relative "livr/rule.rb"
7
+ require_relative "livr/aliased_rule.rb"
8
+ require_relative "livr/rules/common.rb"
9
+ require_relative "livr/rules/string.rb"
10
+ require_relative "livr/rules/numeric.rb"
11
+ require_relative "livr/rules/special.rb"
12
+ require_relative "livr/rules/modifiers.rb"
13
+ require_relative "livr/rules/meta.rb"
14
+
15
+ module LIVR
16
+ DEFAULT_RULES = {
17
+ required: Rules::Common::Required,
18
+ not_empty: Rules::Common::NotEmpty,
19
+ not_empty_list: Rules::Common::NotEmptyList,
20
+ any_object: Rules::Common::AnyObject,
21
+
22
+ string: Rules::String::String,
23
+ eq: Rules::String::Eq,
24
+ one_of: Rules::String::OneOf,
25
+ max_length: Rules::String::MaxLength,
26
+ min_length: Rules::String::MinLength,
27
+ length_equal: Rules::String::LengthEqual,
28
+ length_between: Rules::String::LengthBetween,
29
+ like: Rules::String::Like,
30
+
31
+ integer: Rules::Numeric::Integer,
32
+ positive_integer: Rules::Numeric::PositiveInteger,
33
+ decimal: Rules::Numeric::Decimal,
34
+ positive_decimal: Rules::Numeric::PositiveDecimal,
35
+ max_number: Rules::Numeric::MaxNumber,
36
+ min_number: Rules::Numeric::MinNumber,
37
+ number_between: Rules::Numeric::NumberBetween,
38
+
39
+ email: Rules::Special::Email,
40
+ equal_to_field: Rules::Special::EqualToField,
41
+ url: Rules::Special::Url,
42
+ iso_date: Rules::Special::IsoDate,
43
+
44
+ default: Rules::Modifiers::Default,
45
+ trim: Rules::Modifiers::Trim,
46
+ to_lc: Rules::Modifiers::ToLc,
47
+ to_uc: Rules::Modifiers::ToUc,
48
+ remove: Rules::Modifiers::Remove,
49
+ leave_only: Rules::Modifiers::LeaveOnly,
50
+
51
+ nested_object: Rules::Meta::NestedObject,
52
+ variable_object: Rules::Meta::VariableObject,
53
+ list_of: Rules::Meta::ListOf,
54
+ list_of_objects: Rules::Meta::ListOfObjects,
55
+ list_of_different_objects: Rules::Meta::ListOfDifferentObjects,
56
+ or: Rules::Meta::Or,
57
+ }.with_indifferent_access
58
+
59
+ Validator.register_default_rules(DEFAULT_RULES)
60
+ 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
+