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,68 @@
1
+ module LIVR
2
+ module Rules
3
+ module Modifiers
4
+ class Default < Rule
5
+ def initialize(default_value)
6
+ @default_value = default_value
7
+ end
8
+
9
+ def call(value, user_data, field_results)
10
+ if is_no_value(value)
11
+ field_results << @default_value
12
+ end
13
+ return
14
+ end
15
+ end
16
+
17
+ class Trim < Rule
18
+ def call(value, user_data, field_results)
19
+ return if is_no_value(value) || value.is_a?(Hash)
20
+ field_results << value.to_s.strip
21
+ return
22
+ end
23
+ end
24
+
25
+ class ToLc < Rule
26
+ def call(value, user_data, field_results)
27
+ return if is_no_value(value) || value.is_a?(Hash)
28
+ field_results << value.to_s.downcase
29
+ return
30
+ end
31
+ end
32
+
33
+ class ToUc < Rule
34
+ def call(value, user_data, field_results)
35
+ return if is_no_value(value) || value.is_a?(Hash)
36
+ field_results << value.to_s.upcase
37
+ return
38
+ end
39
+ end
40
+
41
+ class Remove < Rule
42
+ def initialize(chars)
43
+ @chars = chars
44
+ @re = Regexp.compile("[#{Regexp.quote(@chars)}]")
45
+ end
46
+
47
+ def call(value, user_data, field_results)
48
+ return if is_no_value(value) || value.is_a?(Hash)
49
+ field_results << value.to_s.gsub(@re, '')
50
+ return
51
+ end
52
+ end
53
+
54
+ class LeaveOnly < Rule
55
+ def initialize(chars)
56
+ @chars = chars
57
+ @re = Regexp.compile("[^#{Regexp.quote(@chars)}]")
58
+ end
59
+
60
+ def call(value, user_data, field_results)
61
+ return if is_no_value(value) || value.is_a?(Hash)
62
+ field_results << value.to_s.gsub(@re, '')
63
+ return
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,136 @@
1
+ module LIVR
2
+ module Rules
3
+ module Numeric
4
+
5
+ class Integer < Rule
6
+ def call(value, user_data, field_results)
7
+ return if is_no_value(value)
8
+ return 'FORMAT_ERROR' if !is_primitive(value)
9
+
10
+ value_int = Integer(value.to_s) rescue nil
11
+ if value_int.nil?
12
+ return "NOT_INTEGER"
13
+ end
14
+
15
+ field_results << value_int
16
+ return
17
+ end
18
+ end
19
+
20
+
21
+ class PositiveInteger < Rule
22
+ def call(value, user_data, field_results)
23
+ return if is_no_value(value)
24
+ return 'FORMAT_ERROR' if !is_primitive(value)
25
+
26
+ value_int = Integer(value.to_s) rescue nil
27
+
28
+ return "NOT_POSITIVE_INTEGER" if value_int.nil?
29
+ return "NOT_POSITIVE_INTEGER" unless value_int.positive?
30
+
31
+ field_results << value_int
32
+ return
33
+ end
34
+ end
35
+
36
+ class Decimal < Rule
37
+ def call(value, user_data, field_results)
38
+ return if is_no_value(value)
39
+ return 'FORMAT_ERROR' if !is_primitive(value)
40
+
41
+ value_int = Float(value.to_s) rescue nil
42
+ return "NOT_DECIMAL" if value_int.nil?
43
+
44
+ field_results << value_int
45
+ return
46
+ end
47
+ end
48
+
49
+
50
+ class PositiveDecimal < Rule
51
+ def call(value, user_data, field_results)
52
+ return if is_no_value(value)
53
+ return 'FORMAT_ERROR' if !is_primitive(value)
54
+
55
+ value_float = Float(value.to_s) rescue nil
56
+ return "NOT_POSITIVE_DECIMAL" if value_float.nil?
57
+ return "NOT_POSITIVE_DECIMAL" unless value_float.positive?
58
+
59
+ field_results << value_float
60
+ return
61
+ end
62
+ end
63
+
64
+ class MaxNumber < Rule
65
+ def initialize(max_number)
66
+ @max_number = max_number
67
+ end
68
+
69
+ def call(value, user_data, field_results)
70
+ return if is_no_value(value)
71
+ return 'FORMAT_ERROR' if !is_primitive(value)
72
+
73
+ value = Float(value.to_s) rescue nil
74
+ if value.nil?
75
+ return "NOT_NUMBER"
76
+ end
77
+
78
+ if value > @max_number
79
+ return "TOO_HIGH"
80
+ else
81
+ field_results << value
82
+ return
83
+ end
84
+ end
85
+ end
86
+
87
+ class MinNumber < Rule
88
+ def initialize(min_number)
89
+ @min_number = min_number
90
+ end
91
+
92
+ def call(value, user_data, field_results)
93
+ return if is_no_value(value)
94
+ return 'FORMAT_ERROR' if !is_primitive(value)
95
+
96
+ value = Float(value.to_s) rescue nil
97
+ if value.nil?
98
+ return "NOT_NUMBER"
99
+ end
100
+
101
+ if value < @min_number
102
+ return "TOO_LOW"
103
+ else
104
+ field_results << value
105
+ return
106
+ end
107
+ end
108
+ end
109
+
110
+ class NumberBetween < Rule
111
+ def initialize(min_number, max_number)
112
+ @min_number = min_number
113
+ @max_number = max_number
114
+ end
115
+
116
+ def call(value, user_data, field_results)
117
+ return if is_no_value(value)
118
+ return 'FORMAT_ERROR' if !is_primitive(value)
119
+
120
+ value = Float(value.to_s) rescue nil
121
+ if value.nil?
122
+ return "NOT_NUMBER"
123
+ end
124
+
125
+
126
+ return "TOO_LOW" if value < @min_number
127
+ return "TOO_HIGH" if value > @max_number
128
+
129
+ field_results << value
130
+ return
131
+ end
132
+ end
133
+
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,65 @@
1
+ module LIVR
2
+ module Rules
3
+ module Special
4
+
5
+ class Email < Rule
6
+ def call(value, user_data, field_results)
7
+ return if is_no_value(value)
8
+ return 'FORMAT_ERROR' if !is_primitive(value)
9
+
10
+ value = value.to_s
11
+ email_re = /^([\w\-_+]+(?:\.[\w\-_+]+)*)@((?:[\w\-]+\.)*\w[\w\-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i
12
+ return "WRONG_EMAIL" unless email_re.match(value)
13
+ return "WRONG_EMAIL" if /\@.*\@/.match(value)
14
+ return "WRONG_EMAIL" if /\@.*_/.match(value)
15
+ return
16
+ end
17
+ end
18
+
19
+ class EqualToField < Rule
20
+ def initialize(field)
21
+ @field = field
22
+ end
23
+
24
+ def call(value, user_data, field_results)
25
+ return if is_no_value(value)
26
+ return 'FORMAT_ERROR' if !is_primitive(value)
27
+
28
+ return "FIELDS_NOT_EQUAL" if value != user_data[@field]
29
+ end
30
+ end
31
+
32
+ class Url < Rule
33
+ URL_RE_STR = '^(?:(?:http|https)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[0-1]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))\\.?|localhost)(?::\\d{2,5})?(?:[/?#]\\S*)?$'
34
+ URL_RE = Regexp.compile(URL_RE_STR, "i")
35
+ MAX_URL_LENGTH = 2083
36
+
37
+ def call(value, user_data, field_results)
38
+ return if is_no_value(value)
39
+ return 'FORMAT_ERROR' if !is_primitive(value)
40
+
41
+ if value.length < MAX_URL_LENGTH && URL_RE.match(value)
42
+ return
43
+ else
44
+ 'WRONG_URL'
45
+ end
46
+ end
47
+ end
48
+
49
+ class IsoDate < Rule
50
+ def call(value, user_data, field_results)
51
+ return if is_no_value(value)
52
+ return 'FORMAT_ERROR' if !is_primitive(value)
53
+
54
+ return "WRONG_DATE" unless value.length == "YYYY-MM-DD".length
55
+
56
+ date = Date.strptime(value, '%Y-%m-%d') rescue nil
57
+ unless date
58
+ return "WRONG_DATE"
59
+ end
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,150 @@
1
+ module LIVR
2
+ module Rules
3
+ module String
4
+
5
+ class String < Rule
6
+ def call(value, user_data, field_results)
7
+ return if value.in? [nil, ""]
8
+ return 'FORMAT_ERROR' unless is_primitive(value)
9
+
10
+ field_results << value.to_s
11
+
12
+ return nil
13
+ end
14
+ end
15
+
16
+ class Eq < Rule
17
+ def initialize(allowed_value)
18
+ @allowed_value = allowed_value
19
+ end
20
+
21
+ def call(value, user_data, field_results)
22
+ return if is_no_value(value)
23
+ return 'FORMAT_ERROR' unless is_primitive(value)
24
+
25
+ if value.to_s == @allowed_value.to_s
26
+ field_results << @allowed_value
27
+ return
28
+ end
29
+
30
+ return 'NOT_ALLOWED_VALUE'
31
+ end
32
+ end
33
+
34
+ class OneOf < Rule
35
+ def initialize(*allowed_values)
36
+ @allowed_values = allowed_values.flatten
37
+ end
38
+
39
+ def call(value, user_data, field_results)
40
+ return if is_no_value(value)
41
+ return 'FORMAT_ERROR' unless is_primitive(value)
42
+
43
+ @allowed_values.each do |allowed_value|
44
+ if allowed_value.to_s == value.to_s
45
+ field_results << allowed_value
46
+ return
47
+ end
48
+ end
49
+
50
+ return 'NOT_ALLOWED_VALUE'
51
+ end
52
+ end
53
+
54
+ class MaxLength < Rule
55
+ def initialize(max_length)
56
+ @max_length = max_length
57
+ end
58
+
59
+ def call(value, user_data, field_results)
60
+ return if value.in? [nil, ""]
61
+ return 'FORMAT_ERROR' unless is_primitive(value)
62
+
63
+ return 'TOO_LONG' if value.to_s.length > @max_length
64
+ field_results << value.to_s
65
+ return
66
+ end
67
+ end
68
+
69
+ class MinLength < Rule
70
+ def initialize(min_length)
71
+ @min_length = min_length
72
+ end
73
+
74
+ def call(value, user_data, field_results)
75
+ return if is_no_value(value)
76
+ return 'FORMAT_ERROR' unless is_primitive(value)
77
+ if value.to_s.length < @min_length
78
+ return 'TOO_SHORT'
79
+ end
80
+
81
+ field_results << value.to_s
82
+ return
83
+ end
84
+ end
85
+
86
+ class LengthEqual < Rule
87
+ def initialize(length)
88
+ @length = length
89
+ end
90
+
91
+ def call(value, user_data, field_results)
92
+ return if value.in? [nil, ""]
93
+ return 'FORMAT_ERROR' unless is_primitive(value)
94
+
95
+ value = value.to_s
96
+ return 'TOO_SHORT' if value.length < @length
97
+ return 'TOO_LONG' if value.length > @length
98
+
99
+ field_results << value
100
+
101
+ return
102
+ end
103
+ end
104
+
105
+ class LengthBetween < Rule
106
+ def initialize(min_length, max_length)
107
+ @min_length = min_length
108
+ @max_length = max_length
109
+ end
110
+
111
+ def call(value, user_data, field_results)
112
+ return if value.in? [nil, ""]
113
+ return 'FORMAT_ERROR' unless is_primitive(value)
114
+
115
+ value = value.to_s
116
+ return 'TOO_SHORT' if value.length < @min_length
117
+ return 'TOO_LONG' if value.length > @max_length
118
+
119
+ field_results << value
120
+
121
+ return
122
+ end
123
+ end
124
+
125
+ class Like < Rule
126
+ def initialize(re_str, flags=nil)
127
+ @re_str = re_str
128
+ @flags = flags
129
+ end
130
+
131
+ def call(value, user_data, field_results)
132
+ return if value.in? [nil, ""]
133
+ return 'FORMAT_ERROR' unless is_primitive(value)
134
+
135
+ value = value.to_s
136
+ regexp = Regexp.compile(@re_str, @flags)
137
+
138
+ unless regexp.match(value)
139
+ return 'WRONG_FORMAT'
140
+ end
141
+
142
+ field_results << value
143
+
144
+ return
145
+ end
146
+ end
147
+
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,137 @@
1
+ module LIVR
2
+ class Validator
3
+ def initialize(rules, is_auto_trim=false)
4
+ @rules = rules
5
+ @is_prepared = false
6
+ @validator_builders = {}
7
+ @validators = {}
8
+ @is_auto_trim = is_auto_trim
9
+
10
+ register_default_rules
11
+ end
12
+
13
+ def self.register_default_rules(rules)
14
+ @@default_rules ||= {}
15
+ @@default_rules.merge!(rules.with_indifferent_access)
16
+ end
17
+
18
+ def register_aliased_rule(_alias)
19
+ # binding.pry
20
+ # @validator_builders
21
+ register_rules( _alias["name"] => AliasedRule.new(_alias) )
22
+ # @@default_rules[_alias["name"]] = AliasedRule.new(_alias)
23
+ end
24
+
25
+ def prepare
26
+ @rules.each do |field, field_rules|
27
+ field_rules = Array.wrap(field_rules)
28
+ @validators[field] = field_rules.map do |field_rule|
29
+ rule_name, rule_args = parse_rule(field_rule)
30
+ build_validator(rule_name, rule_args)
31
+ end
32
+ @is_prepared = true
33
+ end
34
+ self
35
+ end
36
+
37
+ def validate(user_data)
38
+ prepare unless @is_prepared
39
+
40
+ unless user_data.is_a?(Hash)
41
+ @errors = 'FORMAT_ERROR'
42
+ return
43
+ end
44
+
45
+ if @is_auto_trim
46
+ user_data = auto_trim(user_data)
47
+ end
48
+
49
+ @result = {}
50
+ @errors = {}
51
+
52
+ @validators.each do |field, validators|
53
+ next if validators.blank?
54
+ next if !@rules.has_key?(field)
55
+
56
+ value = user_data[field]
57
+ validators.each do |validator|
58
+ field_results = []
59
+ field_value = @result.fetch(field, value)
60
+ error_code = validator.call(field_value, user_data, field_results)
61
+
62
+ if error_code
63
+ @errors[field] = error_code
64
+ break
65
+ elsif field_results.present?
66
+ @result[field] = field_results.first
67
+ elsif user_data.has_key?(field) && !@result.has_key?(field)
68
+ @result[field] = value
69
+ end
70
+ end
71
+ end
72
+
73
+ if @errors.present?
74
+ return false
75
+ else
76
+ @errors = nil
77
+ return @result
78
+ end
79
+ end
80
+
81
+ def register_rules(rules)
82
+ @validator_builders.merge!(rules)
83
+ self
84
+ end
85
+
86
+ def get_errors
87
+ @errors
88
+ end
89
+
90
+ private
91
+
92
+ def register_default_rules
93
+ register_rules(@@default_rules || [])
94
+ end
95
+
96
+ def parse_rule(livr_rule)
97
+ name = nil
98
+ args = nil
99
+
100
+ case livr_rule
101
+ when Hash
102
+ name = livr_rule.keys.first
103
+ args = Array.wrap(livr_rule[name])
104
+ else
105
+ name = livr_rule
106
+ args = []
107
+ end
108
+
109
+ [ name, args ]
110
+ end
111
+
112
+ def build_validator(name, args)
113
+ if @validator_builders[name].blank?
114
+ raise "Rule ['#{name}'] not registered"
115
+ end
116
+ @validator_builders[name].new(*args)
117
+ end
118
+
119
+ private
120
+
121
+ def auto_trim(user_data)
122
+ case user_data
123
+ when String
124
+ user_data.strip
125
+ when Array
126
+ user_data.map{|v| auto_trim(v) }
127
+ when Hash
128
+ user_data.each do |key, value|
129
+ user_data[key] = auto_trim(value)
130
+ end
131
+ else
132
+ user_data
133
+ end
134
+ end
135
+
136
+ end
137
+ end