validate-params 0.6.1 → 0.7.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7ca97c7e091dd9ec8f28cb7fcfe146ec315e4d7513f145b0a27015c5ecf826d
4
- data.tar.gz: 9b6159617d663834cf65707aa80a51e5e411dc03f218588e9136069494269ce7
3
+ metadata.gz: c8a3bd014c84bdbaf778f5fc1e3c5b1e666fcf1ff9ab95107b509defffb42dd8
4
+ data.tar.gz: e2e3a30f811d7551df3f863ca54c5347f6f3c8c729e494d3649e67b71580e8ea
5
5
  SHA512:
6
- metadata.gz: 5738ecc1bec5808caaa44a71633beb13e0e2ffe77fea4921afea41d1e2d44852833f2f6783b2fbb05cd8f4b140587051a1b5008d0020d13166eb2fb8a059e12b
7
- data.tar.gz: 7d688728061b1a044b564ad199649828d961f0b9bcc21f3b3b19861723048fa2ff5eaad6527e758052c9aebdd04fda5068998c957d62063125a98f866e0ce403
6
+ metadata.gz: 45b0c42c93eea9f538c52a1fd90df22d6b0dab828eec6f6be89359f8f52d4c287507547247c5f05c4859099c4dab73b04085a269c44972190fa5b2ab12235d0f
7
+ data.tar.gz: 86250638fe0a6963d71ee7b6842cd754f95ddccff639e5caed9f6acdc4eeb1caaed13d3ccedfc361220b6afc755cc005942cf98f3ca5809e27e86d29a1d31b94
data/.rubocop.yml CHANGED
@@ -1,13 +1,365 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.7
2
+ TargetRubyVersion: 2.7.0
3
3
 
4
+ # https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions
5
+
6
+ # No blank line after access modifiers
7
+ Layout/EmptyLinesAroundAccessModifier:
8
+ EnforcedStyle: only_before
9
+
10
+ # Hard to use with WSL2
11
+ Layout/EndOfLine:
12
+ Enabled: false
13
+
14
+ # First element shall always be relative to the first position of the line where the opening bracket is
15
+ Layout/FirstArrayElementIndentation:
16
+ EnforcedStyle: consistent
17
+
18
+ # First key shall always be relative to the first position of the line where the opening brace is
19
+ Layout/FirstHashElementIndentation:
20
+ EnforcedStyle: consistent
21
+
22
+ # Table-like left alignment of keys, hash rockets, and values
23
+ Layout/HashAlignment:
24
+ EnforcedHashRocketStyle: table
25
+
26
+ # Method definitions after access modifiers isolated calls need one extra level of indentation
27
+ Layout/IndentationConsistency:
28
+ EnforcedStyle: indented_internal_methods
29
+
30
+ # The second operand should be indented is binary operations that span more than one line
31
+ Layout/MultilineOperationIndentation:
32
+ EnforcedStyle: indented
33
+
34
+ # Braces around single line blocks, do..end around multi-line blocks, except for multi-line blocks
35
+ # whose return value is being chained with another method
36
+ Style/BlockDelimiters:
37
+ EnforcedStyle: braces_for_chaining
38
+
39
+ # Enforce the block end operator to go on its own line in empty methods
40
+ Style/EmptyMethod:
41
+ EnforcedStyle: expanded
42
+
43
+ # Enforce absence of braces around hash literal as a last array item
44
+ Style/HashAsLastArrayItem:
45
+ EnforcedStyle: no_braces
46
+
47
+ # Use double quotes for string literals
4
48
  Style/StringLiterals:
5
- Enabled: true
6
49
  EnforcedStyle: double_quotes
7
50
 
51
+ # Use double quotes inside expressions in interpolated strings
8
52
  Style/StringLiteralsInInterpolation:
9
- Enabled: true
10
53
  EnforcedStyle: double_quotes
11
54
 
55
+ # Use %w or %W for arrays of words whose element count is greater than or equal to 5
56
+ Style/WordArray:
57
+ MinSize: 5
58
+
59
+ Style/BlockComments:
60
+ Enabled: false
61
+
62
+ Style/ClassAndModuleChildren:
63
+ Enabled: false
64
+
65
+ Style/Documentation:
66
+ Enabled: false
67
+
68
+ Style/HashSyntax:
69
+ EnforcedShorthandSyntax: never
70
+
71
+ Style/FrozenStringLiteralComment:
72
+ Enabled: false
73
+
74
+ Bundler/OrderedGems:
75
+ Enabled: false
76
+
77
+ Metrics/AbcSize:
78
+ Enabled: false
79
+
80
+ Metrics/BlockLength:
81
+ Enabled: false
82
+
83
+ Metrics/BlockNesting:
84
+ Enabled: false
85
+
86
+ Metrics/ClassLength:
87
+ Enabled: false
88
+
89
+ Metrics/CyclomaticComplexity:
90
+ Enabled: false
91
+
92
+ Metrics/MethodLength:
93
+ Enabled: false
94
+
95
+ Metrics/ModuleLength:
96
+ Enabled: false
97
+
98
+ Metrics/ParameterLists:
99
+ Enabled: false
100
+
101
+ Metrics/PerceivedComplexity:
102
+ Enabled: false
103
+
104
+ # ┌──────────────────────────────────────────────────────────┐
105
+ # │TODO: Consider refactoring and applying the following cops│
106
+ # └──────────────────────────────────────────────────────────┘
107
+
108
+ Style/ClassVars:
109
+ Enabled: false
110
+
111
+ Style/CombinableLoops:
112
+ Enabled: false
113
+
114
+ Style/For:
115
+ Enabled: false
116
+
117
+ Style/FloatDivision:
118
+ Enabled: false
119
+
120
+ Style/GlobalVars:
121
+ Enabled: false
122
+
123
+ Style/GuardClause:
124
+ Enabled: false
125
+
126
+ Style/HashLikeCase:
127
+ Enabled: false
128
+
129
+ Style/IdenticalConditionalBranches:
130
+ Enabled: false
131
+
132
+ Style/IfUnlessModifier:
133
+ Enabled: false
134
+
135
+ Style/InfiniteLoop:
136
+ Enabled: false
137
+
138
+ Style/InverseMethods:
139
+ Enabled: false
140
+
141
+ Style/KeywordParametersOrder:
142
+ Enabled: false
143
+
144
+ Style/Lambda:
145
+ Enabled: false
146
+
147
+ Style/LineEndConcatenation:
148
+ Enabled: false
149
+
150
+ Style/MixinUsage:
151
+ Enabled: false
152
+
153
+ Style/NegatedIf:
154
+ Enabled: false
155
+
156
+ Style/Next:
157
+ Enabled: false
158
+
159
+ Style/Not:
160
+ Enabled: false
161
+
162
+ Style/NumericLiterals:
163
+ Enabled: false
164
+
165
+ Style/MultilineBlockChain:
166
+ Enabled: false
167
+
168
+ Style/MultilineIfModifier:
169
+ Enabled: false
170
+
171
+ Style/MultipleComparison:
172
+ Enabled: false
173
+
174
+ Style/MultilineTernaryOperator:
175
+ Enabled: false
176
+
177
+ Style/MutableConstant:
178
+ Enabled: false
179
+
180
+ Style/NestedParenthesizedCalls:
181
+ Enabled: false
182
+
183
+ Style/NestedTernaryOperator:
184
+ Enabled: false
185
+
186
+ Style/NumericLiteralPrefix:
187
+ Enabled: false
188
+
189
+ Style/NumericPredicate:
190
+ Enabled: false
191
+
192
+ Style/OptionalBooleanParameter:
193
+ Enabled: false
194
+
195
+ Style/OrAssignment:
196
+ Enabled: false
197
+
198
+ Style/PerlBackrefs:
199
+ Enabled: false
200
+
201
+ Style/PreferredHashMethods:
202
+ Enabled: false
203
+
204
+ Style/RaiseArgs:
205
+ Enabled: false
206
+
207
+ Style/RedundantAssignment:
208
+ Enabled: false
209
+
210
+ Style/RedundantFetchBlock:
211
+ Enabled: false
212
+
213
+ Style/RedundantInterpolation:
214
+ Enabled: false
215
+
216
+ Style/RedundantRegexpEscape:
217
+ Enabled: false
218
+
219
+ Style/RedundantSelf:
220
+ Enabled: false
221
+
222
+ Style/RegexpLiteral:
223
+ Enabled: false
224
+
225
+ Style/RescueModifier:
226
+ Enabled: false
227
+
228
+ Style/RescueStandardError:
229
+ Enabled: false
230
+
231
+ Style/SafeNavigation:
232
+ Enabled: false
233
+
234
+ Style/SignalException:
235
+ Enabled: false
236
+
237
+ Style/SlicingWithRange:
238
+ Enabled: false
239
+
240
+ Style/SoleNestedConditional:
241
+ Enabled: false
242
+
243
+ Style/StringConcatenation:
244
+ Enabled: false
245
+
246
+ Style/StructInheritance:
247
+ Enabled: false
248
+
249
+ Style/SymbolArray:
250
+ Enabled: false
251
+
252
+ Style/SymbolProc:
253
+ Enabled: false
254
+
255
+ Style/UnlessElse:
256
+ Enabled: true
257
+
258
+ Style/WhileUntilDo:
259
+ Enabled: false
260
+
261
+ Style/WhileUntilModifier:
262
+ Enabled: false
263
+
264
+ Lint/AssignmentInCondition:
265
+ Enabled: false
266
+
267
+ Lint/BinaryOperatorWithIdenticalOperands:
268
+ Enabled: false
269
+
270
+ Lint/BooleanSymbol:
271
+ Enabled: false
272
+
273
+ Lint/CircularArgumentReference:
274
+ Enabled: false
275
+
276
+ Lint/DisjunctiveAssignmentInConstructor:
277
+ Enabled: false
278
+
279
+ Lint/DuplicateMethods:
280
+ Enabled: false
281
+
282
+ Lint/EmptyConditionalBody:
283
+ Enabled: false
284
+
285
+ Lint/EmptyWhen:
286
+ Enabled: false
287
+
288
+ Style/IfInsideElse:
289
+ Enabled: false
290
+
291
+ Lint/IneffectiveAccessModifier:
292
+ Enabled: false
293
+
294
+ Lint/MissingSuper:
295
+ Enabled: false
296
+
297
+ Lint/NestedMethodDefinition:
298
+ Enabled: false
299
+
300
+ Lint/NonDeterministicRequireOrder:
301
+ Enabled: false
302
+
303
+ Lint/ParenthesesAsGroupedExpression:
304
+ Enabled: false
305
+
306
+ Lint/RedundantWithIndex:
307
+ Enabled: false
308
+
309
+ Lint/RequireParentheses:
310
+ Enabled: false
311
+
312
+ Lint/RescueException:
313
+ Enabled: false
314
+
315
+ Lint/ShadowedArgument:
316
+ Enabled: false
317
+
318
+ Lint/SuppressedException:
319
+ Enabled: false
320
+
321
+ Lint/ToJSON:
322
+ Enabled: false
323
+
324
+ Lint/UnusedBlockArgument:
325
+ Enabled: false
326
+
327
+ Lint/UnusedMethodArgument:
328
+ Enabled: false
329
+
330
+ Lint/UriRegexp:
331
+ Enabled: false
332
+
333
+ Lint/UselessAccessModifier:
334
+ Enabled: false
335
+
12
336
  Layout/LineLength:
13
- Max: 120
337
+ Enabled: false
338
+
339
+ Naming/AccessorMethodName:
340
+ Enabled: false
341
+
342
+ Naming/MemoizedInstanceVariableName:
343
+ Enabled: false
344
+
345
+ Naming/MethodParameterName:
346
+ Enabled: false
347
+
348
+ Naming/PredicateName:
349
+ Enabled: false
350
+
351
+ Naming/VariableNumber:
352
+ Enabled: false
353
+
354
+ # ┌──────────────────────────────────────────────────────────┐
355
+ # │Enabled pending cops. Remove when added to default config │
356
+ # └──────────────────────────────────────────────────────────┘
357
+
358
+ Style/StringChars:
359
+ Enabled: true
360
+
361
+ Style/RedundantInitialize:
362
+ Enabled: true
363
+
364
+ Style/CaseEquality:
365
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.7.0] - 2023-05-30
4
+
5
+ - Added type support for casting params into types
6
+ - Added support for Array of types [String, Integer]
7
+
3
8
  ## [0.5.2] - 2023-05-29
4
9
 
5
10
  - Support to handle HTML and JSON response formats
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- validate-params (0.6.1)
4
+ validate-params (0.7.1)
5
5
  activesupport (>= 6.1.0)
6
+ i18n (>= 1.6)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -26,6 +26,8 @@ class TestController < ActionController::Base
26
26
  p.param :name, String, default: "John Doe"
27
27
  p.param :occurred_on, Date, required: true, default: proc { Date.today }
28
28
  p.param :quantity, Integer, required: true, in: [1, 2, 3]
29
+ p.param :user_ids, Array, of: Integer, default: [1, 2, 3]
30
+ p.param :states, Array, of: String, default: ["active", "inactive"]
29
31
  p.param :date_of_birth, Hash do |pp|
30
32
  pp.param :gt, Date
31
33
  pp.param :lt, Date
@@ -46,6 +48,18 @@ end
46
48
 
47
49
  If the parameters are valid, the controller action will be executed as normal. If the parameters are invalid, a **400 Bad Request** response will be returned with a JSON body containing the errors, or an empty HTML response.
48
50
 
51
+ ```json
52
+ {
53
+ "success": false,
54
+ "errors": [
55
+ {
56
+ "message": "hired_on must be a valid Date"
57
+ },
58
+
59
+ ]
60
+ }
61
+ ```
62
+
49
63
  ## Format
50
64
 
51
65
  By default responses are returned in JSON format. To return responses as an empty HTML response, change the :format options in the validate_params methods to :html.
@@ -0,0 +1,12 @@
1
+ version: '3'
2
+
3
+ services:
4
+ app:
5
+ image: ruby:3.1.4
6
+ working_dir: /app
7
+ volumes:
8
+ - ./:/app
9
+ - bundler:/usr/local/bundle/
10
+
11
+ volumes:
12
+ bundler:
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ValidateParams
4
+ module Validatable
5
+ class ParamBuilder
6
+ def initialize(parent_field = nil)
7
+ @parent_field = parent_field
8
+ @params_validations = []
9
+ end
10
+
11
+ def param(field, type, options = {})
12
+ return { field: field, type: type, options: options } if @parent_field.nil?
13
+
14
+ @params_validations << { field: { @parent_field => field }, type: type, options: options }
15
+ @params_validations
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/inflector"
4
+
5
+ module ValidateParams
6
+ module Validatable
7
+ class ParamValidator
8
+ def self.call(**args)
9
+ new(**args).call
10
+ end
11
+
12
+ def initialize(type:, field:, value:, errors:, options: {})
13
+ @type = type
14
+ @field = field
15
+ @value = value
16
+ @errors = errors
17
+ @options = options
18
+ end
19
+
20
+ def call
21
+ return if @value.blank? && !@options[:required]
22
+
23
+ if @value.blank? && @options[:required]
24
+ @errors << { message: required_error_message }
25
+ return
26
+ end
27
+
28
+ send(@type.to_s.underscore)
29
+ end
30
+
31
+ private
32
+ def array
33
+ return if Types::Array.valid?(@value, of: @options[:of])
34
+
35
+ @errors << { message: error_message }
36
+ end
37
+
38
+ def date
39
+ return if Types::Date.valid?(@value)
40
+
41
+ @errors << { message: error_message }
42
+ end
43
+
44
+ def date_time
45
+ return if Types::DateTime.valid?(@value)
46
+
47
+ @errors << { message: error_message }
48
+ end
49
+
50
+ def integer
51
+ unless Types::Integer.valid?(@value)
52
+ @errors << { message: error_message }
53
+ return
54
+ end
55
+
56
+ validate_inclusion if @options[:in].present?
57
+ end
58
+
59
+ def string
60
+ validate_inclusion if @options[:in].present?
61
+ end
62
+
63
+ def validate_inclusion
64
+ return if @options[:in].include?(value)
65
+
66
+ @errors << {
67
+ message: I18n.t("validate_params.invalid_in", param: error_param_name),
68
+ valid_values: @options[:in]
69
+ }
70
+ end
71
+
72
+ def error_param_name
73
+ case @field
74
+ when Array
75
+ "#{@field[0]}[#{@field[1]}]"
76
+ when Hash
77
+ @field.map { |k, v| "#{k}[#{v}]" }.first
78
+ else
79
+ @field
80
+ end
81
+ end
82
+
83
+ def error_message
84
+ I18n.t("validate_params.invalid_type", param: error_param_name, type: @type)
85
+ end
86
+
87
+ def required_error_message
88
+ I18n.t("validate_params.required", param: error_param_name)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ValidateParams
4
+ class Types
5
+ class Array
6
+ def self.valid?(value, of: String)
7
+ case of.to_s
8
+ when "Integer"
9
+ value.all? { |item| Types::Integer.valid?(item) }
10
+ else
11
+ true
12
+ end
13
+ end
14
+
15
+ def self.cast(raw_value, of: String)
16
+ case of.to_s
17
+ when "Integer"
18
+ raw_value.map { |item| Types::Integer.cast(item) }
19
+ else
20
+ raw_value
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,19 +1,32 @@
1
- module ValidateParams
2
- class Types
3
- class Date
4
- def self.valid?(value)
5
- value = value.to_s
6
- return false if !/\d{4}-\d{2}-\d{2}/.match?(value)
7
-
8
- parsed_date = begin
9
- ::Date.strptime(value, "%Y-%m-%d")
10
- rescue StandardError
11
- nil
12
- end
13
- return false if parsed_date.nil?
14
- return false if parsed_date.year > 9999
15
- true
16
- end
17
- end
18
- end
19
- end
1
+ # frozen_string_literal: true
2
+
3
+ module ValidateParams
4
+ class Types
5
+ class Date
6
+ FORMAT = "%Y-%m-%d"
7
+
8
+ def self.valid?(value)
9
+ value = value.to_s
10
+ return false unless /\d{4}-\d{2}-\d{2}/.match?(value)
11
+
12
+ parsed_date = begin
13
+ ::Date.strptime(value, FORMAT)
14
+ rescue StandardError
15
+ nil
16
+ end
17
+ return false if parsed_date.nil?
18
+ return false if parsed_date.year > 9999
19
+
20
+ true
21
+ end
22
+
23
+ def self.cast(raw_value, **)
24
+ return raw_value if raw_value.is_a?(::Date)
25
+
26
+ ::Date.strptime(raw_value.to_s, FORMAT)
27
+ rescue StandardError
28
+ raw_value
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ValidateParams
2
4
  class Types
3
5
  class DateTime
@@ -7,6 +9,14 @@ module ValidateParams
7
9
  rescue ArgumentError, TypeError
8
10
  false
9
11
  end
12
+
13
+ def self.cast(raw_value, **)
14
+ return raw_value if raw_value.is_a?(::Time)
15
+
16
+ Time.at(Integer(raw_value))
17
+ rescue ArgumentError, TypeError
18
+ raw_value
19
+ end
10
20
  end
11
21
  end
12
- end
22
+ end
@@ -1,10 +1,15 @@
1
- module ValidateParams
2
- class Types
3
- class Integer
4
- def self.valid?(value)
5
- value = value.to_s
6
- /\A[-+]?\d+\z/ === value
7
- end
8
- end
9
- end
10
- end
1
+ # frozen_string_literal: true
2
+
3
+ module ValidateParams
4
+ class Types
5
+ class Integer
6
+ def self.valid?(value)
7
+ /\A[-+]?\d+\z/ === value.to_s
8
+ end
9
+
10
+ def self.cast(raw_value, **)
11
+ raw_value.to_i
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ValidateParams
4
+ class Types
5
+ class String
6
+ def self.cast(raw_value, **)
7
+ raw_value.to_s
8
+ end
9
+ end
10
+ end
11
+ end
@@ -3,6 +3,11 @@
3
3
  require "validate_params/types/date"
4
4
  require "validate_params/types/date_time"
5
5
  require "validate_params/types/integer"
6
+ require "validate_params/types/array"
7
+ require_relative "param_builder"
8
+ require_relative "param_validator"
9
+
10
+ require "active_support/concern"
6
11
 
7
12
  module ValidateParams
8
13
  module Validatable
@@ -48,142 +53,99 @@ module ValidateParams
48
53
  end
49
54
 
50
55
  private
51
-
52
- def build_error_message(param, type)
53
- I18n.t("validate_params.invalid_type", param: param, type: type)
54
- end
55
-
56
- def build_required_message(param)
57
- I18n.t("validate_params.required", param: param)
58
- end
59
-
60
- def error_param_name(field)
61
- case field
62
- when Array
63
- "#{field[0]}[#{field[1]}]"
64
- when Hash
65
- field.map { |k, v| "#{k}[#{v}]" }.first
66
- else
67
- field
68
- end
69
- end
70
-
71
- def set_params_defaults
72
- params_validations.each do |params_validation|
73
- next if params_validation[:options][:default].blank?
74
-
75
- if params_validation[:field].is_a?(Hash)
76
- params_validation[:field].each_key do |key|
77
- # Skip in case hash is configured and string is passed
78
- next if params.dig(key).is_a? Hash
79
- next if params.dig(key, params_validation[:field][key])
80
-
56
+ def set_params_defaults
57
+ params_validations.each do |params_validation|
58
+ next unless params_validation[:options].key?(:default)
59
+
60
+ if params_validation[:field].is_a?(Hash)
61
+ params_validation[:field].each_key do |key|
62
+ # Skip in case hash is configured and string is passed
63
+ next if hashlike?(params[key])
64
+ next if params.dig(key, params_validation[:field][key])
65
+
66
+ value = if params_validation[:options][:default].is_a?(Proc)
67
+ params_validation[:options][:default].call
68
+ else
69
+ params_validation[:options][:default]
70
+ end
71
+
72
+ params[key] ||= {}
73
+ params[key][params_validation[:field][key]] = value
74
+ end
75
+ else
81
76
  value = if params_validation[:options][:default].is_a?(Proc)
82
77
  params_validation[:options][:default].call
83
78
  else
84
79
  params_validation[:options][:default]
85
80
  end
86
- params.merge!(key => { params_validation[:field][key] => value })
87
- end
88
- else
89
- value = if params_validation[:options][:default].is_a?(Proc)
90
- params_validation[:options][:default].call
91
- else
92
- params_validation[:options][:default]
93
- end
94
81
 
95
- params[params_validation[:field]] ||= value
82
+ params[params_validation[:field]] ||= value
83
+ end
96
84
  end
97
85
  end
98
- end
99
-
100
- def perform_validate_params
101
- return unless controller_action.present? && controller_action == action_name.to_sym
102
-
103
- errors = []
104
86
 
105
- for params_validation in params_validations
106
- # Skip in case hash is configured and string is passed
107
- next if params_validation[:field].is_a?(Hash) &&
108
- params.dig(params_validation[:field].keys.first).is_a?(String)
87
+ def cast_param_values
88
+ ActionController::Parameters
89
+ params_validations.each do |params_validation|
90
+ if params_validation[:field].is_a?(Hash)
91
+ params_validation[:field].each_key do |key|
92
+ next unless hashlike?(params[key])
109
93
 
110
- parameter_value = if params_validation[:field].is_a? Hash
111
- params.dig(params_validation[:field].keys.first,
112
- params_validation[:field][params_validation[:field].keys.first])
113
- else
114
- params[params_validation[:field]]
115
- end
94
+ value = params.dig(key, params_validation[:field][key])
95
+ next if value.blank?
116
96
 
117
- next if parameter_value.blank? && !params_validation[:options][:required]
97
+ params[key][params_validation[:field][key]] = Types.const_get(params_validation[:type].name).cast(value, of: params_validation.dig(:options, :of))
98
+ end
99
+ else
100
+ value = params[params_validation[:field]]
101
+ next if value.blank?
118
102
 
119
- if parameter_value.blank? && params_validation[:options][:required]
120
- errors << { message: build_required_message(error_param_name(params_validation[:field])) }
121
- next
122
- end
123
-
124
- case params_validation[:type].to_s
125
- when "Date"
126
- unless ValidateParams::Types::Date.valid?(parameter_value)
127
- errors << {
128
- message: build_error_message(error_param_name(params_validation[:field]), params_validation[:type])
129
- }
130
- end
131
- when "DateTime"
132
- unless ValidateParams::Types::DateTime.valid?(parameter_value)
133
- errors << {
134
- message: build_error_message(error_param_name(params_validation[:field]), params_validation[:type])
135
- }
136
- end
137
- when "Integer"
138
- unless ValidateParams::Types::Integer.valid?(parameter_value)
139
- errors << {
140
- message: build_error_message(error_param_name(params_validation[:field]), params_validation[:type])
141
- }
142
- next
143
- end
144
-
145
- parameter_value = parameter_value.to_i
146
- if params_validation[:options][:in].present? && !params_validation[:options][:in].include?(parameter_value)
147
- errors << {
148
- message: I18n.t("validate_params.invalid_in", param: error_param_name(params_validation[:field])),
149
- valid_values: params_validation[:options][:in]
150
- }
151
- end
152
- when "String"
153
- parameter_value = parameter_value.to_s
154
- if params_validation[:options][:in].present? && !params_validation[:options][:in].include?(parameter_value)
155
- errors << {
156
- message: I18n.t("validate_params.invalid_in", param: error_param_name(params_validation[:field])),
157
- valid_values: params_validation[:options][:in]
158
- }
103
+ params[params_validation[:field]] = Types.const_get(params_validation[:type].name).cast(value, of: params_validation.dig(:options, :of))
159
104
  end
160
105
  end
161
106
  end
162
107
 
163
- return if errors.empty?
164
-
165
- case response_format
166
- when :html
167
- head :bad_request
168
- else
169
- render json: { success: false, errors: errors }, status: :bad_request
170
- end
171
- end
108
+ def perform_validate_params
109
+ return unless controller_action.present? && controller_action == action_name.to_sym
110
+
111
+ errors = []
112
+
113
+ params_validations.each do |params_validation|
114
+ # Skip in case hash is configured and string is passed
115
+ next if params_validation[:field].is_a?(Hash) &&
116
+ params[params_validation[:field].keys.first].is_a?(String)
117
+
118
+ parameter_value = if params_validation[:field].is_a? Hash
119
+ params.dig(params_validation[:field].keys.first,
120
+ params_validation[:field][params_validation[:field].keys.first])
121
+ else
122
+ params[params_validation[:field]]
123
+ end
124
+
125
+ ParamValidator.call(
126
+ type: params_validation[:type],
127
+ field: params_validation[:field],
128
+ value: parameter_value,
129
+ errors: errors,
130
+ options: params_validation[:options]
131
+ )
132
+ end
172
133
 
173
- class ParamBuilder
174
- def initialize(parent_field = nil)
175
- @parent_field = parent_field
176
- @params_validations = []
177
- end
134
+ if errors.empty?
135
+ cast_param_values
136
+ return
137
+ end
178
138
 
179
- def param(field, type, options = {})
180
- unless @parent_field
181
- return { field: field, type: type, options: options }
139
+ case response_format
140
+ when :html
141
+ head :bad_request
142
+ else
143
+ render json: { success: false, errors: errors }, status: :bad_request
182
144
  end
145
+ end
183
146
 
184
- @params_validations << { field: { @parent_field => field }, type: type, options: options }
185
- @params_validations
147
+ def hashlike?(obj)
148
+ obj.is_a?(Hash) || obj.is_a?(ActionController::Parameters)
186
149
  end
187
- end
188
150
  end
189
151
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ValidateParams
4
- VERSION = "0.6.1"
4
+ VERSION = "0.7.1"
5
5
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  require_relative "validate_params/version"
4
4
  require_relative "validate_params/validatable"
5
- Dir[File.join(__dir__, 'validate_params/types', '*.rb')].each { |file| require file }
6
- Dir[File.join(__dir__, 'validate_params/validators', '*.rb')].each { |file| require file }
5
+
6
+ Dir[File.join(__dir__, "validate_params/types", "*.rb")].sort.each { |file| require file }
7
7
 
8
8
  module ValidateParams
9
9
  class Error < StandardError; end
@@ -30,4 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "rspec", "~> 3.0"
31
31
 
32
32
  spec.add_dependency "activesupport", ">= 6.1.0"
33
+ spec.add_dependency "i18n", ">= 1.6"
33
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validate-params
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - dcherevatenko
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-29 00:00:00.000000000 Z
11
+ date: 2023-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: 6.1.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: i18n
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '1.6'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '1.6'
83
97
  description: Provides a clean DSL to validate params for controller actions.
84
98
  email:
85
99
  - 'denis.cherevatenko@peopleforce.io '
@@ -95,12 +109,16 @@ files:
95
109
  - README.md
96
110
  - Rakefile
97
111
  - config/locales/en.yml
112
+ - docker-compose.yml
98
113
  - lib/validate_params.rb
114
+ - lib/validate_params/param_builder.rb
115
+ - lib/validate_params/param_validator.rb
116
+ - lib/validate_params/types/array.rb
99
117
  - lib/validate_params/types/date.rb
100
118
  - lib/validate_params/types/date_time.rb
101
119
  - lib/validate_params/types/integer.rb
120
+ - lib/validate_params/types/string.rb
102
121
  - lib/validate_params/validatable.rb
103
- - lib/validate_params/validators/date.rb
104
122
  - lib/validate_params/version.rb
105
123
  - sig/validate_params.rbs
106
124
  - validate_params.gemspec
File without changes