easy_params 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5a19f19d20a42ef6a6ba3e606298c3dbf696a22c9dcdc9e42a8ffe48e1e67db
4
- data.tar.gz: fce70967d59989d5e650289483d5437f4ebb80793d49b3a446d252796017117c
3
+ metadata.gz: 8a23a79fb06b0d9c02b836dc314e420f1339b20473d740f4427a6f1a9e740efe
4
+ data.tar.gz: e1ddbee8e7b5aa08fb3e9f1f2dc925ecc179a8f95ac3276e2aeb839f7e3cbe9d
5
5
  SHA512:
6
- metadata.gz: 3f690f1a17df11da94e8f707c99f97854aec48ca890320c0345159286c4e10ac19448a5b3a6557936c6076b4bf4e886cd51841ef394b3a205c91626a680b598f
7
- data.tar.gz: c43521492ce73961d7ff7fb562ba7b8ba944f03c928a8c68298f8f6f168c21ab698d4acdf3fe2dd073296bec99418cf14adffd8446cc751541b32136b452e972
6
+ metadata.gz: 9a9968cc2201493bd774562cc9590d47537b870238ac5b64b33167c9b084feb14c067b6b4ee9a36f54abdff18a198c8d99474b8dc531fab45ebbffd61ae08c11
7
+ data.tar.gz: 11d7e883cc4a229c14b9323e94f8372e2f38d2c238e883884c2fe733bab4918be6ad62c13da09621fbb0e8b5b85405d7d2d9cb8197abc3cbf0d762b6657c2a7d
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- easy_params (0.3.0)
4
+ easy_params (0.4.0)
5
5
  activemodel (>= 3.2, < 8)
6
6
  dry-struct (~> 1.4)
7
7
  dry-types (~> 1.5)
@@ -9,46 +9,55 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- activemodel (7.0.4.3)
13
- activesupport (= 7.0.4.3)
14
- activesupport (7.0.4.3)
12
+ activemodel (7.1.2)
13
+ activesupport (= 7.1.2)
14
+ activesupport (7.1.2)
15
+ base64
16
+ bigdecimal
15
17
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ connection_pool (>= 2.2.5)
19
+ drb
16
20
  i18n (>= 1.6, < 2)
17
21
  minitest (>= 5.1)
22
+ mutex_m
18
23
  tzinfo (~> 2.0)
19
24
  ast (2.4.2)
25
+ base64 (0.2.0)
26
+ bigdecimal (3.1.5)
20
27
  coderay (1.1.3)
21
28
  concurrent-ruby (1.2.2)
29
+ connection_pool (2.4.1)
22
30
  diff-lcs (1.4.4)
23
31
  docile (1.3.5)
24
- dry-configurable (0.14.0)
32
+ drb (2.2.0)
33
+ ruby2_keywords
34
+ dry-core (1.0.1)
25
35
  concurrent-ruby (~> 1.0)
26
- dry-core (~> 0.6)
27
- dry-container (0.9.0)
36
+ zeitwerk (~> 2.6)
37
+ dry-inflector (1.0.0)
38
+ dry-logic (1.5.0)
28
39
  concurrent-ruby (~> 1.0)
29
- dry-configurable (~> 0.13, >= 0.13.0)
30
- dry-core (0.7.1)
31
- concurrent-ruby (~> 1.0)
32
- dry-inflector (0.3.0)
33
- dry-logic (1.2.0)
34
- concurrent-ruby (~> 1.0)
35
- dry-core (~> 0.5, >= 0.5)
36
- dry-struct (1.4.0)
37
- dry-core (~> 0.5, >= 0.5)
38
- dry-types (~> 1.5)
40
+ dry-core (~> 1.0, < 2)
41
+ zeitwerk (~> 2.6)
42
+ dry-struct (1.6.0)
43
+ dry-core (~> 1.0, < 2)
44
+ dry-types (>= 1.7, < 2)
39
45
  ice_nine (~> 0.11)
40
- dry-types (1.5.1)
46
+ zeitwerk (~> 2.6)
47
+ dry-types (1.7.2)
48
+ bigdecimal (~> 3.0)
41
49
  concurrent-ruby (~> 1.0)
42
- dry-container (~> 0.3)
43
- dry-core (~> 0.5, >= 0.5)
44
- dry-inflector (~> 0.1, >= 0.1.2)
45
- dry-logic (~> 1.0, >= 1.0.2)
50
+ dry-core (~> 1.0)
51
+ dry-inflector (~> 1.0)
52
+ dry-logic (~> 1.4)
53
+ zeitwerk (~> 2.6)
46
54
  i18n (1.14.1)
47
55
  concurrent-ruby (~> 1.0)
48
56
  ice_nine (0.11.2)
49
57
  json (2.6.3)
50
58
  method_source (1.0.0)
51
- minitest (5.18.1)
59
+ minitest (5.20.0)
60
+ mutex_m (0.2.0)
52
61
  parallel (1.23.0)
53
62
  parser (3.2.2.3)
54
63
  ast (~> 2.4.1)
@@ -89,6 +98,7 @@ GEM
89
98
  rubocop-ast (1.29.0)
90
99
  parser (>= 3.2.1.0)
91
100
  ruby-progressbar (1.13.0)
101
+ ruby2_keywords (0.0.5)
92
102
  simplecov (0.21.2)
93
103
  docile (~> 1.1)
94
104
  simplecov-html (~> 0.11)
@@ -98,6 +108,7 @@ GEM
98
108
  tzinfo (2.0.6)
99
109
  concurrent-ruby (~> 1.0)
100
110
  unicode-display_width (2.4.2)
111
+ zeitwerk (2.6.12)
101
112
 
102
113
  PLATFORMS
103
114
  ruby
data/README.md CHANGED
@@ -51,10 +51,10 @@ end
51
51
  Validation messages for nested attributes will look like this.
52
52
  ```ruby
53
53
  {
54
- :"sections/0/id"=>an_instance_of(Array),
55
- :"sections/0/post/id"=>an_instance_of(Array),
56
- :"post/id"=>an_instance_of(Array),
57
- :"post/sections/0/id"=>an_instance_of(Array)
54
+ :"sections[0].id"=>an_instance_of(Array),
55
+ :"sections[0].post.id"=>an_instance_of(Array),
56
+ :"post.id"=>an_instance_of(Array),
57
+ :"post.sections[0].id"=>an_instance_of(Array)
58
58
  }
59
59
  ```
60
60
  Optionally you can use more compact form
@@ -11,55 +11,93 @@ module EasyParams
11
11
  'EasyParams::Base'
12
12
  end
13
13
 
14
- %w[Integer Decimal Float Bool String Array Date DateTime Time Struct StructDSL].each do |type|
15
- send(:define_singleton_method, type.underscore) { EasyParams::Types.const_get(type) }
16
- end
17
-
18
14
  validate do
19
15
  validate_nested
20
16
  end
21
17
 
18
+ # %w[Integer Decimal Float Bool String Date DateTime Time Array Struct StructDSL].each do |type|
19
+ %w[Integer Decimal Float Bool String Date DateTime Time].each do |type_name|
20
+ send(:define_singleton_method, type_name.underscore) do |param_name, default: nil, normalize: nil, **validations|
21
+ type = EasyParams::Types.const_get(type_name)
22
+ type = type.default(default) if default
23
+ type = type.constructor { |value| value == Dry::Types::Undefined ? value : normalize.call(value) } if normalize
24
+ validates param_name, **validations if validations.any?
25
+ public_send(:attribute, param_name, type)
26
+ end
27
+ end
28
+
29
+ def self.each(param_name, normalize: nil, **validations, &block)
30
+ validates param_name, **validations if validations.any?
31
+ type = EasyParams::Types::Each
32
+ type = type.constructor { |value| value == Dry::Types::Undefined ? value : normalize.call(value) } if normalize
33
+ public_send(:attribute, param_name, type, &block)
34
+ end
35
+
36
+ def self.has(param_name, normalize: nil, **validations, &block)
37
+ validates param_name, **validations if validations.any?
38
+ type = EasyParams::Types::Struct
39
+ type = type.constructor { |value| value == Dry::Types::Undefined ? value : normalize.call(value) } if normalize
40
+ public_send(:attribute, param_name, type, &block)
41
+ end
42
+
43
+ def self.array(param_name, of:, normalize: nil, **validations, &block)
44
+ validates param_name, **validations if validations.any?
45
+ of_type = EasyParams::Types.const_get(of.to_s.camelcase)
46
+ type = EasyParams::Types::Array
47
+ type = type.constructor { |value| value == Dry::Types::Undefined ? value : normalize.call(value) } if normalize
48
+ public_send(:attribute, param_name, type.of(of_type), &block)
49
+ end
50
+
51
+ def self.param(method_name, type_name, of: nil, default: nil, **validations, &block)
52
+ type = EasyParams::Types.const_get(type_name.to_s.camelcase)
53
+ type = type.default(default) if default
54
+ type = type.of(EasyParams::Types.const_get(of.to_s.camelcase)) if of && type_name != :each
55
+ validates method_name, **validations if validations.any?
56
+ public_send(:attribute, method_name, type, &block)
57
+ end
58
+
22
59
  private
23
60
 
24
61
  def validate_nested
25
- attributes.each(&run_nested_validations)
62
+ attributes.each do |_, value|
63
+ case value
64
+ when *EasyParams::Types::ARRAY_OF_STRUCTS_TYPES_LIST
65
+ value.each(&:valid?)
66
+ when *EasyParams::Types::STRUCT_TYPES_LIST
67
+ value.valid?
68
+ end
69
+ end
70
+ attributes.each(&aggregate_nested_errors)
26
71
  end
27
72
 
28
- def run_nested_validations
73
+ def aggregate_nested_errors
29
74
  proc do |attr_name, value, array_index, error_key_prefix|
30
75
  case value
31
- when Array
76
+ when *EasyParams::Types::ARRAY_OF_STRUCTS_TYPES_LIST
32
77
  value.each.with_index do |element, i|
33
- run_nested_validations[attr_name, element, i, error_key_prefix]
78
+ aggregate_nested_errors[attr_name, element, "[#{i}]", error_key_prefix]
34
79
  end
35
- when self.class.struct
36
- handle_struct_validation(value, error_key_prefix, attr_name, array_index)
80
+ when *EasyParams::Types::STRUCT_TYPES_LIST
81
+ handle_nested_errors(value, error_key_prefix, attr_name, array_index)
37
82
  end
38
83
  end
39
84
  end
40
85
 
41
- def handle_struct_validation(value, error_key_prefix, attr_name, array_index)
42
- if value.invalid?
43
- error_key_components = [error_key_prefix, attr_name, array_index]
44
- attr_error_key_prefix = error_key_components.compact.join('/')
45
- add_errors_on_top_level(value, attr_error_key_prefix)
46
- end
47
- value.attributes.each do |nested_attr_name, nested_value|
48
- run_nested_validations[nested_attr_name, nested_value, nil, attr_error_key_prefix]
49
- end
86
+ def handle_nested_errors(value, error_key_prefix, attr_name, array_index)
87
+ return if value.errors.blank?
88
+
89
+ error_key_components = [error_key_prefix, attr_name, array_index]
90
+ attr_error_key_prefix = error_key_components.compact.join('.').gsub(/\.\[(\d+)\]/, '[\1]')
91
+ add_errors_on_top_level(value, attr_error_key_prefix)
50
92
  end
51
93
 
52
94
  if defined? ActiveModel::Error
53
95
  def add_errors_on_top_level(value, attr_error_key_prefix)
54
- value.errors.each do |error|
55
- next unless error.options[:message]
56
-
57
- errors.add("#{attr_error_key_prefix}/#{error.attribute}", error.options[:message])
58
- end
96
+ value.errors.each { |error| errors.add("#{attr_error_key_prefix}.#{error.attribute}", error.message) }
59
97
  end
60
98
  else
61
99
  def add_errors_on_top_level(value, attr_error_key_prefix)
62
- value.errors.each { |key, message| errors.add("#{attr_error_key_prefix}/#{key}", message) }
100
+ value.errors.each { |key, message| errors.add("#{attr_error_key_prefix}.#{key}", message) }
63
101
  end
64
102
  end
65
103
  end
@@ -3,15 +3,19 @@
3
3
  module EasyParams
4
4
  module Types
5
5
  Struct = EasyParams::Base.meta(omittable: true)
6
- StructDSL = ::Class.new(EasyParams::Base).extend(EasyParams::DSL).meta(omittable: true)
6
+ Has = EasyParams::Base.meta(omittable: true)
7
7
  Integer = Dry::Types['params.integer'].optional.meta(omittable: true).default(nil)
8
8
  Decimal = Dry::Types['params.decimal'].optional.meta(omittable: true).default(nil)
9
9
  Float = Dry::Types['params.float'].optional.meta(omittable: true).default(nil)
10
- Bool = Dry::Types['strict.bool'].optional.meta(omittable: true).default(nil)
10
+ Bool = Dry::Types['params.bool'].optional.meta(omittable: true).default(nil)
11
11
  String = Dry::Types['string'].optional.meta(omittable: true).default(nil)
12
- Array = Dry::Types['array'].of(Struct).meta(omittable: true).default([])
12
+ Array = Dry::Types['array'].meta(omittable: true).default([])
13
+ Each = Dry::Types['array'].of(Struct).meta(omittable: true).default([])
13
14
  Date = Dry::Types['params.date'].optional.meta(omittable: true).default(nil)
14
15
  DateTime = Dry::Types['params.date_time'].optional.meta(omittable: true).default(nil)
15
16
  Time = Dry::Types['params.time'].optional.meta(omittable: true).default(nil)
17
+
18
+ STRUCT_TYPES_LIST = [Struct, Has].freeze
19
+ ARRAY_OF_STRUCTS_TYPES_LIST = [Array.of(Struct), Each].freeze
16
20
  end
17
21
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EasyParams
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/easy_params.rb CHANGED
@@ -4,7 +4,6 @@ require 'dry-struct'
4
4
  require 'dry-types'
5
5
  require 'active_model'
6
6
  require 'easy_params/base'
7
- require 'easy_params/dsl'
8
7
  require 'easy_params/types'
9
8
  require 'easy_params/version'
10
9
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy_params
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrii Baran
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-24 00:00:00.000000000 Z
11
+ date: 2024-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -82,7 +82,6 @@ files:
82
82
  - easy_params.gemspec
83
83
  - lib/easy_params.rb
84
84
  - lib/easy_params/base.rb
85
- - lib/easy_params/dsl.rb
86
85
  - lib/easy_params/types.rb
87
86
  - lib/easy_params/version.rb
88
87
  homepage: https://github.com/andriy-baran/easy_params
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EasyParams
4
- # Makes definition more compact
5
- # Do not use if your attributes have name like
6
- # integer, decimal, float, bool, string, array, date, datetime, time, struct
7
- module DSL
8
- def each(&block)
9
- array.of(struct_dsl, &block)
10
- end
11
-
12
- def has(&block)
13
- struct_dsl(&block)
14
- end
15
-
16
- def method_missing(method_name, *args, &block)
17
- public_send(:attribute, method_name, *args, &block)
18
- end
19
-
20
- def respond_to_missing?(*)
21
- true
22
- end
23
- end
24
- end