easy_params 0.4.1 → 0.5.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 +4 -4
- data/Gemfile.lock +8 -32
- data/README.md +30 -30
- data/easy_params.gemspec +1 -5
- data/lib/easy_params/base.rb +64 -73
- data/lib/easy_params/types/collection.rb +50 -0
- data/lib/easy_params/types/generic.rb +44 -0
- data/lib/easy_params/types/struct.rb +18 -0
- data/lib/easy_params/types.rb +31 -12
- data/lib/easy_params/validation.rb +51 -0
- data/lib/easy_params/version.rb +1 -1
- data/lib/easy_params.rb +5 -2
- metadata +6 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e5797272eae09e65c24f46558c801f19126e71e4ca940bdfaeecfaab478fe7d
|
4
|
+
data.tar.gz: 95d1a80d4f0635013658713c6dccc45058e707cae9e90ec88036313c673819ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e76c8c64f7568d0ef3633eb3ca86a1cf1f03f331d528aa7a941c8197a2030dbbeb3fc77149b7dd0416b4776b3a8b547a6e0c451a6e1c3af92835b25e2d6815c
|
7
|
+
data.tar.gz: 82f361cf4ebce4db3ab3bbc9fd7ca196a3dc57a91c3156df1b2e18d443922a900998f58c43b5a12571346de047c1f9e803ad45e109dcb32c028840c44ebf0681
|
data/Gemfile.lock
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
easy_params (0.
|
5
|
-
activemodel (>= 3.2
|
6
|
-
dry-struct (~> 1.4)
|
7
|
-
dry-types (~> 1.5)
|
4
|
+
easy_params (0.5.0)
|
5
|
+
activemodel (>= 3.2)
|
8
6
|
|
9
7
|
GEM
|
10
8
|
remote: https://rubygems.org/
|
11
9
|
specs:
|
12
|
-
activemodel (7.1.
|
13
|
-
activesupport (= 7.1.
|
14
|
-
activesupport (7.1.
|
10
|
+
activemodel (7.1.3)
|
11
|
+
activesupport (= 7.1.3)
|
12
|
+
activesupport (7.1.3)
|
15
13
|
base64
|
16
14
|
bigdecimal
|
17
15
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
@@ -23,40 +21,19 @@ GEM
|
|
23
21
|
tzinfo (~> 2.0)
|
24
22
|
ast (2.4.2)
|
25
23
|
base64 (0.2.0)
|
26
|
-
bigdecimal (3.1.
|
24
|
+
bigdecimal (3.1.6)
|
27
25
|
coderay (1.1.3)
|
28
|
-
concurrent-ruby (1.2.
|
26
|
+
concurrent-ruby (1.2.3)
|
29
27
|
connection_pool (2.4.1)
|
30
28
|
diff-lcs (1.4.4)
|
31
29
|
docile (1.3.5)
|
32
30
|
drb (2.2.0)
|
33
31
|
ruby2_keywords
|
34
|
-
dry-core (1.0.1)
|
35
|
-
concurrent-ruby (~> 1.0)
|
36
|
-
zeitwerk (~> 2.6)
|
37
|
-
dry-inflector (1.0.0)
|
38
|
-
dry-logic (1.5.0)
|
39
|
-
concurrent-ruby (~> 1.0)
|
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)
|
45
|
-
ice_nine (~> 0.11)
|
46
|
-
zeitwerk (~> 2.6)
|
47
|
-
dry-types (1.7.2)
|
48
|
-
bigdecimal (~> 3.0)
|
49
|
-
concurrent-ruby (~> 1.0)
|
50
|
-
dry-core (~> 1.0)
|
51
|
-
dry-inflector (~> 1.0)
|
52
|
-
dry-logic (~> 1.4)
|
53
|
-
zeitwerk (~> 2.6)
|
54
32
|
i18n (1.14.1)
|
55
33
|
concurrent-ruby (~> 1.0)
|
56
|
-
ice_nine (0.11.2)
|
57
34
|
json (2.6.3)
|
58
35
|
method_source (1.0.0)
|
59
|
-
minitest (5.21.
|
36
|
+
minitest (5.21.2)
|
60
37
|
mutex_m (0.2.0)
|
61
38
|
parallel (1.23.0)
|
62
39
|
parser (3.2.2.3)
|
@@ -108,7 +85,6 @@ GEM
|
|
108
85
|
tzinfo (2.0.6)
|
109
86
|
concurrent-ruby (~> 1.0)
|
110
87
|
unicode-display_width (2.4.2)
|
111
|
-
zeitwerk (2.6.12)
|
112
88
|
|
113
89
|
PLATFORMS
|
114
90
|
ruby
|
data/README.md
CHANGED
@@ -4,11 +4,11 @@
|
|
4
4
|
[](https://codeclimate.com/github/andriy-baran/easy_params/maintainability)
|
5
5
|
[](https://codeclimate.com/github/andriy-baran/easy_params/test_coverage)
|
6
6
|
|
7
|
-
Provides an easy way define structure, validation rules, type coercion and set default values for any hash-like structure. It's built on top of `
|
7
|
+
Provides an easy way define structure, validation rules, type coercion and set default values for any hash-like structure. It's built on top of `active_model`.
|
8
8
|
|
9
9
|
## Types
|
10
10
|
|
11
|
-
Dry types are wrapped by class methods. Avaliable types: `integer`, `decimal`, `float`, `bool`, `string`, `array`, `date`, `datetime`, `time
|
11
|
+
Dry types are wrapped by class methods. Avaliable types: `integer`, `decimal`, `float`, `bool`, `string`, `array`, `date`, `datetime`, `time`
|
12
12
|
|
13
13
|
## Installation
|
14
14
|
|
@@ -28,24 +28,39 @@ Or install it yourself as:
|
|
28
28
|
|
29
29
|
## Usage
|
30
30
|
|
31
|
+
To define attribute we have a set of methods which match types list. Ex.
|
32
|
+
```ruby
|
33
|
+
integer(param_name, default: nil, normalize: nil, **validations)
|
34
|
+
```
|
35
|
+
* `:default` provides a value to return if got `nil` as input or there were errors during coersion.
|
36
|
+
* `normalize` a proc or lambda that accepts single argument and changes it in some way. It's get called before coercion.
|
37
|
+
* `validations` mimics `activemodel/validation` can be any supported validation `presence: true, numericality: { only_integer: true, greater_than: 0 }`
|
38
|
+
|
39
|
+
In addition we have special option for an `array` type
|
40
|
+
* `:of` accepts `:integer`, `:decimal`, `:float`, `:bool`, `:string`, `:date`, `:datetime`, `:time` (`:array` is not supported)
|
41
|
+
|
42
|
+
There are two special types:
|
43
|
+
|
44
|
+
| type | method to define | default |
|
45
|
+
|-------------------|------------------|---------|
|
46
|
+
| :struct | has | {} |
|
47
|
+
| :array_of_structs | each | [] |
|
48
|
+
|
31
49
|
```ruby
|
32
50
|
# app/params/api/v2/icqa/move_params.rb
|
33
51
|
class Api::V1::Carts::MoveParams < EasyParams::Base
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
52
|
+
integer :receive_cart_id, presence: { message: "can't be blank" }
|
53
|
+
bool :i_am_sure
|
54
|
+
string :location_code, default: '', presence: { message: "can't be blank" }
|
55
|
+
has :section do
|
56
|
+
string :from
|
57
|
+
string :to
|
40
58
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
validates :option_type_count, :option_type_value, presence: { message: "can't be blank" }
|
59
|
+
array :variant_ids, of: :integer
|
60
|
+
each :options do
|
61
|
+
integer :option_type_count, presence: { message: "can't be blank" }
|
62
|
+
integer :option_type_value, presence: { message: "can't be blank" }
|
46
63
|
end
|
47
|
-
|
48
|
-
validates :receive_cart_id, :location_code, presence: { message: "can't be blank" }
|
49
64
|
end
|
50
65
|
```
|
51
66
|
Validation messages for nested attributes will look like this.
|
@@ -57,21 +72,6 @@ Validation messages for nested attributes will look like this.
|
|
57
72
|
:"post.sections[0].id"=>an_instance_of(Array)
|
58
73
|
}
|
59
74
|
```
|
60
|
-
Optionally you can use more compact form
|
61
|
-
```ruby
|
62
|
-
class MyParams < EasyParams::Base
|
63
|
-
extend EasyParams::DSL
|
64
|
-
|
65
|
-
quantity integer.default(1)
|
66
|
-
posts each do
|
67
|
-
content string.default('')
|
68
|
-
end
|
69
|
-
user has do
|
70
|
-
role string
|
71
|
-
end
|
72
|
-
end
|
73
|
-
```
|
74
|
-
This hovewer has some limitations: for attributes have name like `integer`, `decimal`, `float`, `bool`, `string`, `array`, `date`, `datetime`, `time`, `struct` it won't work as expected.
|
75
75
|
|
76
76
|
More examples here [params_spec.rb](https://github.com/andriy-baran/easy_params/blob/master/spec/easy_params_spec.rb)
|
77
77
|
|
data/easy_params.gemspec
CHANGED
@@ -29,11 +29,7 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
30
|
spec.require_paths = ['lib']
|
31
31
|
|
32
|
-
version_string = ['>= 3.2'
|
32
|
+
version_string = ['>= 3.2']
|
33
33
|
|
34
34
|
spec.add_runtime_dependency 'activemodel', version_string
|
35
|
-
|
36
|
-
# spec.add_dependency 'dry-logic', '~> 0.4.2'
|
37
|
-
spec.add_dependency 'dry-struct', '~> 1.4'
|
38
|
-
spec.add_dependency 'dry-types', '~> 1.5'
|
39
35
|
end
|
data/lib/easy_params/base.rb
CHANGED
@@ -2,99 +2,90 @@
|
|
2
2
|
|
3
3
|
module EasyParams
|
4
4
|
# Implements validations logic and nesting structures
|
5
|
-
class Base
|
6
|
-
include ActiveModel::
|
5
|
+
class Base
|
6
|
+
include ActiveModel::Model
|
7
|
+
include EasyParams::Types::Struct
|
8
|
+
include EasyParams::Validation
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def initialize(params = {})
|
11
|
+
self.class.schema.each do |attr, type|
|
12
|
+
public_send("#{attr}=", type.coerce(params[attr])) if params
|
13
|
+
end
|
12
14
|
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
class << self
|
17
|
+
def name
|
18
|
+
'EasyParams::Base'
|
19
|
+
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
def attribute(param_name, type)
|
22
|
+
attr_accessor param_name
|
23
|
+
|
24
|
+
schema[param_name] = type
|
25
|
+
end
|
26
|
+
|
27
|
+
def schema
|
28
|
+
@schema ||= {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def each(param_name, normalize: nil, **validations, &block)
|
26
32
|
validates param_name, **validations if validations.any?
|
33
|
+
type = EasyParams::Types::Each.with_type(&block)
|
34
|
+
type = customize_type(type, nil, &normalize)
|
27
35
|
public_send(:attribute, param_name, type)
|
28
36
|
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.each(param_name, normalize: nil, optional: nil, **validations, &block)
|
32
|
-
validates param_name, **validations if validations.any?
|
33
|
-
type = EasyParams::Types::Array.of(EasyParams::Types::Struct)
|
34
|
-
type = type.meta(omittable: true) if optional
|
35
|
-
type = type.constructor { |value| value == Dry::Types::Undefined ? value : normalize.call(value) } if normalize
|
36
|
-
public_send(:attribute, param_name, type, &block)
|
37
|
-
end
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
38
|
+
def has(param_name, normalize: nil, **validations, &block)
|
39
|
+
validates param_name, **validations if validations.any?
|
40
|
+
type = Class.new(EasyParams::Types::Struct.class).tap { |c| c.class_eval(&block) }.new
|
41
|
+
type = customize_type(type, nil, &normalize)
|
42
|
+
public_send(:attribute, param_name, type)
|
43
|
+
end
|
46
44
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
public_send(:attribute, param_name, type.of(of_type), &block)
|
54
|
-
end
|
45
|
+
def array(param_name, of:, normalize: nil, **validations)
|
46
|
+
validates param_name, **validations if validations.any?
|
47
|
+
type = EasyParams::Types::Array.of(EasyParams::Types.const_get(of.to_s.camelcase))
|
48
|
+
type = customize_type(type, nil, &normalize)
|
49
|
+
public_send(:attribute, param_name, type)
|
50
|
+
end
|
55
51
|
|
56
|
-
|
52
|
+
private
|
57
53
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
value.each(&:valid?)
|
63
|
-
when *EasyParams::Types::STRUCT_TYPES_LIST
|
64
|
-
value.valid?
|
65
|
-
end
|
54
|
+
def customize_type(type, default, &normalize)
|
55
|
+
type = type.default(default) if default
|
56
|
+
type = type.normalize(&normalize) if normalize
|
57
|
+
type
|
66
58
|
end
|
67
|
-
attributes.each(&aggregate_nested_errors)
|
68
59
|
end
|
69
60
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
when *EasyParams::Types::STRUCT_TYPES_LIST
|
78
|
-
handle_nested_errors(value, error_key_prefix, attr_name, array_index)
|
79
|
-
end
|
61
|
+
%w[Integer Decimal Float Bool String Date DateTime Time].each do |type_name|
|
62
|
+
send(:define_singleton_method,
|
63
|
+
type_name.underscore) do |param_name, default: nil, normalize: nil, **validations|
|
64
|
+
validates param_name, **validations if validations.any?
|
65
|
+
type = EasyParams::Types.const_get(type_name)
|
66
|
+
type = customize_type(type, default, &normalize)
|
67
|
+
public_send(:attribute, param_name, type)
|
80
68
|
end
|
81
69
|
end
|
82
70
|
|
83
|
-
def
|
84
|
-
|
71
|
+
def attributes
|
72
|
+
self.class.schema.to_h { |k, type| [k, type.array? ? send(k).to_a : send(k)] }
|
73
|
+
end
|
85
74
|
|
86
|
-
|
87
|
-
|
88
|
-
add_errors_on_top_level(value, attr_error_key_prefix)
|
75
|
+
validate do
|
76
|
+
validate_nested
|
89
77
|
end
|
90
78
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
79
|
+
def to_h
|
80
|
+
attributes.each.with_object({}) do |(key, value), result|
|
81
|
+
result[key] = case value
|
82
|
+
when EasyParams::Types::StructsCollection
|
83
|
+
value.map(&:to_h)
|
84
|
+
when EasyParams::Types::Struct.class
|
85
|
+
value.to_h
|
86
|
+
else
|
87
|
+
value
|
88
|
+
end
|
98
89
|
end
|
99
90
|
end
|
100
91
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyParams
|
4
|
+
module Types
|
5
|
+
# base interface for array type
|
6
|
+
class Collection < Generic
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def initialize(*attrs, of: nil)
|
10
|
+
super(*attrs)
|
11
|
+
@of_type = of
|
12
|
+
end
|
13
|
+
|
14
|
+
def of(of_type)
|
15
|
+
self.class.new(@title, @default, @normalize_proc, of: of_type, &@coerce_proc)
|
16
|
+
end
|
17
|
+
|
18
|
+
def coerce(value)
|
19
|
+
value = @normalize_proc.call(Array(value)) if @normalize_proc
|
20
|
+
self.class.new(@title, Array(value).map do |v|
|
21
|
+
@of_type.coerce(v)
|
22
|
+
end, @normalize_proc, of: @of_type, &@coerce_proc)
|
23
|
+
end
|
24
|
+
|
25
|
+
def normalize(&block)
|
26
|
+
self.class.new(@title, @default, block, of: @of_type, &@coerce_proc)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.optional
|
30
|
+
self.class.new(@title, @default, @normalize_proc, of: @of_type, &@coerce_proc)
|
31
|
+
end
|
32
|
+
|
33
|
+
def default(value)
|
34
|
+
self.class.new(@title, value, @normalize_proc, of: @of_type, &@coerce_proc)
|
35
|
+
end
|
36
|
+
|
37
|
+
def each(&block)
|
38
|
+
@default.each(&block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# base interface for array of structs type
|
43
|
+
class StructsCollection < Collection
|
44
|
+
def with_type(&block)
|
45
|
+
of_type = Class.new(EasyParams::Types::Struct.class).tap { |c| c.class_eval(&block) }.new
|
46
|
+
self.class.new(@title, @default, @normalize_proc, of: of_type)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyParams
|
4
|
+
module Types
|
5
|
+
# base interface for simple types
|
6
|
+
class Generic
|
7
|
+
def array?
|
8
|
+
@title == :array
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(title, default = nil, normalize_proc = nil, &coerce_proc)
|
12
|
+
@title = title
|
13
|
+
@default = default
|
14
|
+
@coerce_proc = coerce_proc
|
15
|
+
@normalize_proc = normalize_proc
|
16
|
+
end
|
17
|
+
|
18
|
+
def default(value)
|
19
|
+
self.class.new(@title, value, @normalize_proc, &@coerce_proc)
|
20
|
+
end
|
21
|
+
|
22
|
+
def optional
|
23
|
+
self.class.new(@title, @default, @normalize_proc, &@coerce_proc)
|
24
|
+
end
|
25
|
+
|
26
|
+
def optional?
|
27
|
+
@optional
|
28
|
+
end
|
29
|
+
|
30
|
+
def normalize(&block)
|
31
|
+
self.class.new(@title, @default, block, &@coerce_proc)
|
32
|
+
end
|
33
|
+
|
34
|
+
def coerce(value)
|
35
|
+
value = @normalize_proc.call(value) if @normalize_proc
|
36
|
+
return @default if value.nil?
|
37
|
+
|
38
|
+
@coerce_proc.call(value)
|
39
|
+
rescue StandardError
|
40
|
+
@default
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyParams
|
4
|
+
module Types
|
5
|
+
# base interface for struct type
|
6
|
+
module Struct
|
7
|
+
def array?
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def coerce(input)
|
12
|
+
return if input.blank?
|
13
|
+
|
14
|
+
self.class.new(input)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/easy_params/types.rb
CHANGED
@@ -2,18 +2,37 @@
|
|
2
2
|
|
3
3
|
module EasyParams
|
4
4
|
module Types
|
5
|
-
|
6
|
-
Integer = Dry::Types['params.integer'].optional.default(nil)
|
7
|
-
Decimal = Dry::Types['params.decimal'].optional.default(nil)
|
8
|
-
Float = Dry::Types['params.float'].optional.default(nil)
|
9
|
-
Bool = Dry::Types['params.bool'].optional.default(nil)
|
10
|
-
String = Dry::Types['coercible.string'].optional.default(nil)
|
11
|
-
Array = Dry::Types['array'].default([].freeze)
|
12
|
-
Date = Dry::Types['params.date'].optional.default(nil)
|
13
|
-
DateTime = Dry::Types['params.date_time'].optional.default(nil)
|
14
|
-
Time = Dry::Types['params.time'].optional.default(nil)
|
5
|
+
class CoercionError < StandardError; end
|
15
6
|
|
16
|
-
|
17
|
-
|
7
|
+
BOOLEAN_MAP =
|
8
|
+
{ '1' => true, 't' => true, 'true' => true, 'True' => true, 'TRUE' => true, 'T' => true }.merge(
|
9
|
+
{ '0' => false, 'f' => false, 'false' => false, 'False' => false, 'FALSE' => false, 'F' => false }
|
10
|
+
).freeze
|
11
|
+
|
12
|
+
Struct = Class.new(EasyParams::Base).new
|
13
|
+
Array = Collection.new(:array)
|
14
|
+
Each = StructsCollection.new(:array_of_structs)
|
15
|
+
Integer = Generic.new(:integer, &:to_i)
|
16
|
+
Float = Generic.new(:float, &:to_f)
|
17
|
+
String = Generic.new(:string, &:to_s)
|
18
|
+
Decimal = Generic.new(:decimal) { |v| v.to_f.to_d }
|
19
|
+
Bool = Generic.new(:bool) do |v|
|
20
|
+
BOOLEAN_MAP.fetch(v.to_s) { raise CoercionError }
|
21
|
+
end
|
22
|
+
Date = Generic.new(:date) do |v|
|
23
|
+
::Date.parse(v)
|
24
|
+
rescue ArgumentError, RangeError
|
25
|
+
raise CoercionError, 'cannot be coerced'
|
26
|
+
end
|
27
|
+
DateTime = Generic.new(:datetime) do |v|
|
28
|
+
::DateTime.parse(v)
|
29
|
+
rescue ArgumentError
|
30
|
+
raise CoercionError, 'cannot be coerced'
|
31
|
+
end
|
32
|
+
Time = Generic.new(:time) do |v|
|
33
|
+
::Time.parse(v)
|
34
|
+
rescue ArgumentError
|
35
|
+
raise CoercionError, 'cannot be coerced'
|
36
|
+
end
|
18
37
|
end
|
19
38
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyParams
|
4
|
+
# helpers for recursive validation
|
5
|
+
module Validation
|
6
|
+
private
|
7
|
+
|
8
|
+
def validate_nested
|
9
|
+
attributes.each_value do |value|
|
10
|
+
case value
|
11
|
+
when EasyParams::Types::StructsCollection
|
12
|
+
value.each(&:valid?)
|
13
|
+
when EasyParams::Types::Struct.class
|
14
|
+
value.valid?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
attributes.each(&aggregate_nested_errors)
|
18
|
+
end
|
19
|
+
|
20
|
+
def aggregate_nested_errors
|
21
|
+
proc do |attr_name, value, array_index, error_key_prefix|
|
22
|
+
case value
|
23
|
+
when EasyParams::Types::StructsCollection
|
24
|
+
value.each.with_index do |element, i|
|
25
|
+
aggregate_nested_errors[attr_name, element, "[#{i}]", error_key_prefix]
|
26
|
+
end
|
27
|
+
when EasyParams::Types::Struct.class
|
28
|
+
handle_nested_errors(value, error_key_prefix, attr_name, array_index)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def handle_nested_errors(value, error_key_prefix, attr_name, array_index)
|
34
|
+
return if value.errors.blank?
|
35
|
+
|
36
|
+
error_key_components = [error_key_prefix, attr_name, array_index]
|
37
|
+
attr_error_key_prefix = error_key_components.compact.join('.').gsub(/\.\[(\d+)\]/, '[\1]')
|
38
|
+
add_errors_on_top_level(value, attr_error_key_prefix)
|
39
|
+
end
|
40
|
+
|
41
|
+
if defined? ActiveModel::Error
|
42
|
+
def add_errors_on_top_level(value, attr_error_key_prefix)
|
43
|
+
value.errors.each { |error| errors.add("#{attr_error_key_prefix}.#{error.attribute}", error.message) }
|
44
|
+
end
|
45
|
+
else
|
46
|
+
def add_errors_on_top_level(value, attr_error_key_prefix)
|
47
|
+
value.errors.each { |key, message| errors.add("#{attr_error_key_prefix}.#{key}", message) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/easy_params/version.rb
CHANGED
data/lib/easy_params.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'dry-struct'
|
4
|
-
require 'dry-types'
|
5
3
|
require 'active_model'
|
4
|
+
require 'bigdecimal/util'
|
5
|
+
require 'easy_params/types/generic'
|
6
|
+
require 'easy_params/types/collection'
|
7
|
+
require 'easy_params/types/struct'
|
8
|
+
require 'easy_params/validation'
|
6
9
|
require 'easy_params/base'
|
7
10
|
require 'easy_params/types'
|
8
11
|
require 'easy_params/version'
|
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.
|
4
|
+
version: 0.5.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: 2024-01-
|
11
|
+
date: 2024-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -17,9 +17,6 @@ dependencies:
|
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '3.2'
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '8'
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -27,37 +24,6 @@ dependencies:
|
|
27
24
|
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '3.2'
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '8'
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: dry-struct
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '1.4'
|
40
|
-
type: :runtime
|
41
|
-
prerelease: false
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '1.4'
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: dry-types
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '1.5'
|
54
|
-
type: :runtime
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - "~>"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '1.5'
|
61
27
|
description: Dessribe structure, validate and coerce values. Powered by dry-types
|
62
28
|
and dry-struct
|
63
29
|
email:
|
@@ -83,6 +49,10 @@ files:
|
|
83
49
|
- lib/easy_params.rb
|
84
50
|
- lib/easy_params/base.rb
|
85
51
|
- lib/easy_params/types.rb
|
52
|
+
- lib/easy_params/types/collection.rb
|
53
|
+
- lib/easy_params/types/generic.rb
|
54
|
+
- lib/easy_params/types/struct.rb
|
55
|
+
- lib/easy_params/validation.rb
|
86
56
|
- lib/easy_params/version.rb
|
87
57
|
homepage: https://github.com/andriy-baran/easy_params
|
88
58
|
licenses:
|