validate-params 0.10.1 → 0.12.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4bf00d7abf295f6623a9d5662925cca62bea27970d12f7c80bed5f3a38c8771
4
- data.tar.gz: 2eed60863aa7042cf3d49fe2efc27f05eeaffabed8271b9af24ba86b84c569f2
3
+ metadata.gz: 29df4493a4e78d2a93b953b423b01a87870e49e9178720971eba9174aa0a5e1e
4
+ data.tar.gz: 6368b7cbf5240ff8d05ef54a402fc52ec800e181a6104f4219bae02270745b62
5
5
  SHA512:
6
- metadata.gz: 1824e14a25d47becc170f70562028df6106cc16f55e183a59b911147cb513a6f137b1eea8ee622682fb0f1095bd8bb50b190a53ed08ae9cb9246856ecd347501
7
- data.tar.gz: 278a1b7d1e8d36277214e648c000a3f87cce939c9f224fc29f2e2efd2f0fdf7ede037ca9b9e05a9b61b7e79df095d5b9c80d0f20d74793924f591af92bf634a0
6
+ metadata.gz: 63379593455a6bf06bb6d8633b8387d170bc602114e53cd5107cbc7e9e5fee524cb66c86d5e7675a9d4e300cc380d982be8cf8739cf34e59e3d4bc76b1c26d0e
7
+ data.tar.gz: 371f096da45f2eeed375607d1181e227b843b18241c43a9601db90bf8d0357939f65c1413814a7ee031472b504acd776ca72c3d8f1b184a1a05254d938d7de9c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.11.0] - 2023-11-04
4
+
5
+ - Added support for Float type
6
+ - Improved validation for Array type
7
+
3
8
  ## [0.10.0] - 2023-08-28
4
9
 
5
10
  - Added support for IO type to validate file uploads
data/Gemfile CHANGED
@@ -6,4 +6,4 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "rake", "~> 13.0"
9
- gem "rubocop", "~> 1.56"
9
+ gem "rubocop", "~> 1.57"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- validate-params (0.10.1)
4
+ validate-params (0.12.0)
5
5
  activesupport (>= 6.1.0)
6
6
  i18n (>= 1.6)
7
7
 
@@ -28,7 +28,6 @@ GEM
28
28
  tzinfo (~> 2.0)
29
29
  zeitwerk (~> 2.3)
30
30
  ast (2.4.2)
31
- base64 (0.1.1)
32
31
  builder (3.2.4)
33
32
  concurrent-ruby (1.2.2)
34
33
  crass (1.0.6)
@@ -47,7 +46,7 @@ GEM
47
46
  mini_portile2 (~> 2.8.0)
48
47
  racc (~> 1.4)
49
48
  parallel (1.23.0)
50
- parser (3.2.2.3)
49
+ parser (3.2.2.4)
51
50
  ast (~> 2.4.1)
52
51
  racc
53
52
  racc (1.7.1)
@@ -61,7 +60,7 @@ GEM
61
60
  loofah (~> 2.19, >= 2.19.1)
62
61
  rainbow (3.1.1)
63
62
  rake (13.0.6)
64
- regexp_parser (2.8.1)
63
+ regexp_parser (2.8.2)
65
64
  rexml (3.2.6)
66
65
  rspec (3.12.0)
67
66
  rspec-core (~> 3.12.0)
@@ -76,24 +75,23 @@ GEM
76
75
  diff-lcs (>= 1.2.0, < 2.0)
77
76
  rspec-support (~> 3.12.0)
78
77
  rspec-support (3.12.0)
79
- rubocop (1.56.0)
80
- base64 (~> 0.1.1)
78
+ rubocop (1.57.2)
81
79
  json (~> 2.3)
82
80
  language_server-protocol (>= 3.17.0)
83
81
  parallel (~> 1.10)
84
- parser (>= 3.2.2.3)
82
+ parser (>= 3.2.2.4)
85
83
  rainbow (>= 2.2.2, < 4.0)
86
84
  regexp_parser (>= 1.8, < 3.0)
87
85
  rexml (>= 3.2.5, < 4.0)
88
86
  rubocop-ast (>= 1.28.1, < 2.0)
89
87
  ruby-progressbar (~> 1.7)
90
88
  unicode-display_width (>= 2.4.0, < 3.0)
91
- rubocop-ast (1.29.0)
89
+ rubocop-ast (1.30.0)
92
90
  parser (>= 3.2.1.0)
93
91
  ruby-progressbar (1.13.0)
94
92
  tzinfo (2.0.6)
95
93
  concurrent-ruby (~> 1.0)
96
- unicode-display_width (2.4.2)
94
+ unicode-display_width (2.5.0)
97
95
  zeitwerk (2.6.8)
98
96
 
99
97
  PLATFORMS
@@ -104,7 +102,7 @@ DEPENDENCIES
104
102
  bundler (~> 2.0)
105
103
  rake (~> 13.0)
106
104
  rspec (~> 3.0)
107
- rubocop (~> 1.56)
105
+ rubocop (~> 1.57)
108
106
  validate-params!
109
107
 
110
108
  BUNDLED WITH
data/README.md CHANGED
@@ -27,6 +27,7 @@ class TestController < ActionController::Base
27
27
  p.param :occurred_on, Date, required: true, default: proc { Date.today }
28
28
  p.param :per_page, Integer, default: 50, min: 1, max: 50
29
29
  p.param :quantity, Integer, required: true, in: [1, 2, 3]
30
+ p.param :weight, Float
30
31
  p.param :user_ids, Array, of: Integer, default: [1, 2, 3]
31
32
  p.param :states, Array, of: String, default: ["active", "inactive"], reject_blank: true
32
33
  p.param :file, IO, min: 1.byte, max: 1.megabyte
@@ -52,10 +53,11 @@ Here are the following supported types along with operations supported.
52
53
 
53
54
  - String (required, default)
54
55
  - Integer (required, default, min, max, in)
56
+ - Float (required, default, min, max, in)
55
57
  - Date (required, default, min, max)
56
58
  - DateTime (required, default, min, max)
57
59
  - IO (required, min, max)
58
- - Array of: (String|Integer) (default, reject_blank)
60
+ - Array of: (String|Integer|Float) (default, reject_blank)
59
61
  - Hash - Nested block of types
60
62
 
61
63
 
@@ -3,27 +3,60 @@
3
3
  module ValidateParams
4
4
  module Validatable
5
5
  class ParamBuilder
6
- def initialize(parent_field: nil, validations:)
7
- @parent_field = parent_field
8
- @validations = validations
9
- end
6
+ Validation = Struct.new(:field, :type, :options, :children, :parent) do
7
+ def valid?(value, errors)
8
+ ParamValidator.call(
9
+ validation: self,
10
+ value: value,
11
+ errors: errors
12
+ )
10
13
 
11
- def param(field, type, options = {}, &block)
12
- if block
13
- yield(ParamBuilder.new(parent_field: field, validations: @validations))
14
- else
15
- @validations << build_config(field, type, options)
14
+ if children.any?
15
+ case type.to_s
16
+ when "Hash"
17
+ # Skip in case hash is configured and string is passed
18
+ if !value.is_a?(String)
19
+ children.each { |c| c.valid?(value&.[](c.field), errors) }
20
+ end
21
+ when "Array"
22
+ values = value ? Array.wrap(value) : [nil]
23
+ values.each do |item|
24
+ children.each do |child|
25
+ child_value = item[child.field] if item.is_a?(Hash) || item.is_a?(Array)
26
+ child.valid?(child_value, errors)
27
+ end
28
+ end
29
+ else
30
+ raise "Unexpected type: #{type}"
31
+ end
32
+ end
33
+
34
+ errors.empty?
16
35
  end
17
36
  end
18
37
 
19
- private
20
- def build_config(field, type, options)
21
- if @parent_field.nil?
22
- { field: field, type: type, options: options }
23
- else
24
- { field: { @parent_field => field }, type: type, options: options }
38
+ def initialize(parent: nil, validations: [])
39
+ @parent = parent
40
+ @validations = validations
41
+ end
42
+
43
+ def param(field, type, options = {})
44
+ validation = Validation.new(field, type, options, [], @parent)
45
+
46
+ if block_given?
47
+ if ![Array, Hash].include?(type)
48
+ raise "#{type} type cannot have nested definitions, only Array or Hash are supported"
25
49
  end
50
+
51
+ yield ParamBuilder.new(parent: validation)
26
52
  end
53
+
54
+ if @parent
55
+ @parent.children << validation
56
+ else
57
+ @validations << validation
58
+ end
59
+ end
27
60
  end
28
61
  end
29
62
  end
@@ -9,12 +9,13 @@ module ValidateParams
9
9
  new(**args).call
10
10
  end
11
11
 
12
- def initialize(type:, field:, value:, errors:, options: {})
13
- @type = type
14
- @field = field
12
+ attr_reader :validation
13
+
14
+ def initialize(validation:, value:, errors:)
15
+ @validation = validation
15
16
  @value = value
16
17
  @errors = errors
17
- @options = options
18
+ @options = validation.options.presence || {}
18
19
  end
19
20
 
20
21
  def call
@@ -25,7 +26,7 @@ module ValidateParams
25
26
  return
26
27
  end
27
28
 
28
- send(@type.to_s.underscore)
29
+ send(validation.type.to_s.underscore)
29
30
  end
30
31
 
31
32
  private
@@ -72,6 +73,19 @@ module ValidateParams
72
73
  validate_max(formatted_value) if @options[:max].present?
73
74
  end
74
75
 
76
+ def float
77
+ unless Types::Float.valid?(@value)
78
+ @errors << { message: error_message }
79
+ return
80
+ end
81
+
82
+ formatted_value = Types::Float.cast(@value)
83
+
84
+ validate_inclusion if @options[:in].present?
85
+ validate_min(formatted_value) if @options[:min].present?
86
+ validate_max(formatted_value) if @options[:max].present?
87
+ end
88
+
75
89
  def string
76
90
  validate_inclusion if @options[:in].present?
77
91
  end
@@ -116,18 +130,15 @@ module ValidateParams
116
130
  end
117
131
 
118
132
  def error_param_name
119
- case @field
120
- when Array
121
- "#{@field[0]}[#{@field[1]}]"
122
- when Hash
123
- @field.map { |k, v| "#{k}[#{v}]" }.first
133
+ if validation.parent
134
+ "#{validation.parent.field}[#{validation.field}]"
124
135
  else
125
- @field
136
+ validation.field
126
137
  end
127
138
  end
128
139
 
129
140
  def error_message
130
- I18n.t("validate_params.invalid_type", param: error_param_name, type: @type)
141
+ I18n.t("validate_params.invalid_type", param: error_param_name, type: validation.type)
131
142
  end
132
143
 
133
144
  def required_error_message
@@ -3,25 +3,35 @@
3
3
  module ValidateParams
4
4
  class Types
5
5
  class Array
6
- def self.valid?(value, of: String, reject_blank: false, **)
6
+ def self.valid?(value, of: ::String, reject_blank: false, **)
7
+ return false unless value.is_a?(::Array)
8
+
7
9
  val = value
8
- val = val.reject(&:blank?) if reject_blank
10
+ val.reject!(&:blank?) if reject_blank
9
11
 
10
12
  case of.to_s
11
13
  when "Integer"
12
14
  val.all? { |item| Types::Integer.valid?(item) }
15
+ when "Float"
16
+ val.all? { |item| Types::Float.valid?(item) }
17
+ when "String"
18
+ val.all? { |item| item.is_a?(::String) }
19
+ when "Hash"
20
+ val.all? { |item| item.is_a?(::Hash) }
13
21
  else
14
22
  true
15
23
  end
16
24
  end
17
25
 
18
- def self.cast(raw_value, of: String, reject_blank: false, **)
26
+ def self.cast(raw_value, of: ::String, reject_blank: false, **)
19
27
  value = raw_value
20
- value = value.reject!(&:blank?) if reject_blank
28
+ value.reject!(&:blank?) if reject_blank
21
29
 
22
30
  case of.to_s
23
31
  when "Integer"
24
32
  value.map { |item| Types::Integer.cast(item) }
33
+ when "Float"
34
+ value.map { |item| Types::Float.cast(item) }
25
35
  else
26
36
  value
27
37
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ValidateParams
4
+ class Types
5
+ class Float
6
+ def self.valid?(value)
7
+ /\A[-+]?\d+(\.\d+)?\z/ === value.to_s
8
+ end
9
+
10
+ def self.cast(raw_value, **)
11
+ raw_value.to_f
12
+ end
13
+ end
14
+ end
15
+ end
@@ -3,6 +3,7 @@
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/float"
6
7
  require "validate_params/types/array"
7
8
  require "validate_params/types/string"
8
9
  require "validate_params/types/i_o"
@@ -22,14 +23,17 @@ module ValidateParams
22
23
  class_methods do
23
24
  attr_reader :params_validations
24
25
 
25
- def validate_params_for(action, options = {}, &block)
26
+ def validate_params_for(action, options = {})
26
27
  options[:format] ||= :json
27
28
  @params_validations ||= {}
28
29
 
29
30
  Array(action).each do |act|
30
31
  @params_validations[act] ||= { options: options, validations: [] }
31
32
 
32
- yield(ParamBuilder.new(validations: @params_validations[act][:validations])) if block
33
+ if block_given?
34
+ param_builder = ParamBuilder.new(validations: @params_validations[act][:validations])
35
+ yield(param_builder)
36
+ end
33
37
  end
34
38
  end
35
39
  end
@@ -46,29 +50,15 @@ module ValidateParams
46
50
  config = params_validations[action_name.to_sym]
47
51
 
48
52
  config[:validations].each do |validation|
49
- apply_default_values(validation)
50
-
51
- next if validation[:field].is_a?(Hash) &&
52
- params[validation[:field].keys.first].is_a?(String)
53
-
54
- parameter_value = if validation[:field].is_a? Hash
55
- params.dig(validation[:field].keys.first,
56
- validation[:field][validation[:field].keys.first])
57
- else
58
- params[validation[:field]]
59
- end
60
-
61
- ParamValidator.call(
62
- type: validation[:type],
63
- field: validation[:field],
64
- value: parameter_value,
65
- errors: errors,
66
- options: validation[:options]
67
- )
53
+ apply_default_values(params, validation)
54
+ validation.valid?(params[validation.field], errors)
68
55
  end
69
56
 
70
57
  if errors.empty?
71
- cast_param_values(config[:validations])
58
+ config[:validations].each do |validation|
59
+ cast_param_values(params, validation)
60
+ end
61
+
72
62
  return
73
63
  end
74
64
 
@@ -80,57 +70,57 @@ module ValidateParams
80
70
  end
81
71
  end
82
72
 
83
- def apply_default_values(validation)
84
- return unless validation[:options].key?(:default)
73
+ def apply_default_values(params, validation)
74
+ validation.children.each do |sub_validation|
75
+ next if sub_validation.options.blank?
85
76
 
86
- if validation[:field].is_a?(Hash)
87
- validation[:field].each_key do |key|
77
+ if validation.type == Array
78
+ Array(params[validation.field]).each do |sub_params|
79
+ apply_default_values(sub_params, sub_validation)
80
+ end
81
+ elsif validation.type == Hash
88
82
  # Skip in case hash is configured and string is passed
89
- next if hashlike?(params[key])
90
- next if params.dig(key, validation[:field][key])
91
-
92
- value = if validation[:options][:default].is_a?(Proc)
93
- validation[:options][:default].call
94
- else
95
- validation[:options][:default]
96
- end
83
+ next if params[validation.field].is_a?(String)
97
84
 
98
- params[key] ||= {}
99
- params[key][validation[:field][key]] = value
85
+ params[validation.field] ||= {}
86
+ apply_default_values(params[validation.field], sub_validation)
87
+ else
88
+ apply_default_values(params, sub_validation)
100
89
  end
101
- else
102
- value = if validation[:options][:default].is_a?(Proc)
103
- validation[:options][:default].call
104
- else
105
- validation[:options][:default]
106
- end
107
-
108
- params[validation[:field]] ||= value
109
90
  end
91
+
92
+ return if validation.children.any?
93
+
94
+ options = validation.options.presence || {}
95
+ return if !options.key?(:default)
96
+
97
+ value = options[:default].is_a?(Proc) ? options[:default].call : options[:default]
98
+ params[validation.field] ||= value
110
99
  end
111
100
 
112
- def cast_param_values(validations)
113
- validations.each do |validation|
114
- if validation[:field].is_a?(Hash)
115
- validation[:field].each_key do |key|
116
- next unless hashlike?(params[key])
101
+ def cast_param_values(params, validation)
102
+ return unless params
117
103
 
118
- value = params.dig(key, validation[:field][key])
119
- next if value.blank?
104
+ validation.children.each do |sub_validation|
105
+ if validation.type == Hash
106
+ # Skip in case hash is configured and string is passed
107
+ next if params[validation.field].is_a?(String)
120
108
 
121
- params[key][validation[:field][key]] = Types.const_get(validation[:type].name).cast(value, **validation.fetch(:options, {}))
109
+ cast_param_values(params[validation.field], sub_validation)
110
+ elsif validation.type == Array
111
+ params[validation.field].each do |sub_params|
112
+ cast_param_values(sub_params, sub_validation)
122
113
  end
123
- else
124
- value = params[validation[:field]]
125
- next if value.blank?
126
-
127
- params[validation[:field]] = Types.const_get(validation[:type].name).cast(value, **validation.fetch(:options, {}))
128
114
  end
129
115
  end
130
- end
131
116
 
132
- def hashlike?(obj)
133
- obj.is_a?(Hash) || obj.is_a?(ActionController::Parameters)
117
+ return if validation.children.any?
118
+
119
+ value = params[validation.field]
120
+ return if value.blank?
121
+
122
+ options = validation.options.presence || {}
123
+ params[validation.field] = Types.const_get(validation.type.name).cast(value, **options)
134
124
  end
135
125
  end
136
126
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ValidateParams
4
- VERSION = "0.10.1"
4
+ VERSION = "0.12.0"
5
5
  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.10.1
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - dcherevatenko
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-31 00:00:00.000000000 Z
11
+ date: 2024-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -116,6 +116,7 @@ files:
116
116
  - lib/validate_params/types/array.rb
117
117
  - lib/validate_params/types/date.rb
118
118
  - lib/validate_params/types/date_time.rb
119
+ - lib/validate_params/types/float.rb
119
120
  - lib/validate_params/types/i_o.rb
120
121
  - lib/validate_params/types/integer.rb
121
122
  - lib/validate_params/types/string.rb
@@ -123,11 +124,11 @@ files:
123
124
  - lib/validate_params/version.rb
124
125
  - sig/validate_params.rbs
125
126
  - validate_params.gemspec
126
- homepage:
127
+ homepage:
127
128
  licenses:
128
129
  - MIT
129
130
  metadata: {}
130
- post_install_message:
131
+ post_install_message:
131
132
  rdoc_options: []
132
133
  require_paths:
133
134
  - lib
@@ -142,8 +143,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
143
  - !ruby/object:Gem::Version
143
144
  version: '0'
144
145
  requirements: []
145
- rubygems_version: 3.2.3
146
- signing_key:
146
+ rubygems_version: 3.4.10
147
+ signing_key:
147
148
  specification_version: 4
148
149
  summary: Gem to validate params in controllers
149
150
  test_files: []