ruby-livr 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 (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
+