easy_params 0.7.0 → 0.8.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 +1 -1
- data/README.md +98 -1
- data/lib/easy_params/base.rb +34 -3
- data/lib/easy_params/types/collection.rb +2 -3
- data/lib/easy_params/types/struct.rb +4 -0
- data/lib/easy_params/version.rb +1 -1
- data/lib/easy_params.rb +4 -4
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 520468dff4cbd537cef3eec5d4d0c15607e0616143812746c559a7697294bc1c
|
|
4
|
+
data.tar.gz: 338dc40010d0a02ab8819289ad64e9355fa2ee302fbb93ae82723b15a9b8d94c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b0f00c2a25862648b027d96b0491ddfdc6f838cf5fef010c8fa263436afb2ea463f85a3ea8b46ca3839e4036d8a8a73fd98a577fb78f2f8a204a1515b130022f
|
|
7
|
+
data.tar.gz: 86a0f9d29e30d44d40d3af84604d458b8b8cffc190d9e960de3a3858d550161b33970520ea3d3e03d3ad3e221532f0fc28a48abd3882eb0c760a186465328d21
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -10,6 +10,40 @@ Provides an easy way to define structure, validation rules, type coercion, and d
|
|
|
10
10
|
|
|
11
11
|
Available types: `integer`, `decimal`, `float`, `bool`, `string`, `array`, `date`, `datetime`, `time`
|
|
12
12
|
|
|
13
|
+
### Registering Custom Types
|
|
14
|
+
|
|
15
|
+
You can register custom types using `EasyParams.register_type`:
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
# Register a weight type that converts between units
|
|
19
|
+
EasyParams.register_type :weight do |value|
|
|
20
|
+
case value.to_s.downcase
|
|
21
|
+
when /^(\d+(?:\.\d+)?)\s*kg$/i
|
|
22
|
+
$1.to_f
|
|
23
|
+
when /^(\d+(?:\.\d+)?)\s*lbs?$/i
|
|
24
|
+
$1.to_f * 0.453592 # Convert pounds to kg
|
|
25
|
+
when /^(\d+(?:\.\d+)?)\s*g$/i
|
|
26
|
+
$1.to_f / 1000.0 # Convert grams to kg
|
|
27
|
+
else
|
|
28
|
+
value.to_f
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Now you can use the weight type in your params classes
|
|
33
|
+
class PersonParams < EasyParams::Base
|
|
34
|
+
weight :mass, presence: true
|
|
35
|
+
weight :target_weight, default: 70.0
|
|
36
|
+
array :weights, of: :weight, default: [65.0, 70.0]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Usage
|
|
40
|
+
person = PersonParams.new(mass: '75.5 kg', target_weight: '165 lbs')
|
|
41
|
+
# person.mass = 75.5
|
|
42
|
+
# person.target_weight ≈ 74.84 (converted from lbs to kg)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Custom types work with all EasyParams features including validation, arrays, nested structures, and inheritance.
|
|
46
|
+
|
|
13
47
|
## Installation
|
|
14
48
|
|
|
15
49
|
Add this line to your application's Gemfile:
|
|
@@ -80,6 +114,67 @@ There are two special types:
|
|
|
80
114
|
# input: nil => items.map(&:qty) == [2, 1]
|
|
81
115
|
```
|
|
82
116
|
|
|
117
|
+
### Schema Extension
|
|
118
|
+
|
|
119
|
+
You can dynamically extend nested schema definitions using the `#{param_name}_schema` method. This creates a subclass of the original schema that replaces the parent class in the schema, allowing you to add validations, methods, or modify attributes at runtime.
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
class PostParams < EasyParams::Base
|
|
123
|
+
has :post, default: {} do
|
|
124
|
+
integer :id
|
|
125
|
+
string :title
|
|
126
|
+
string :content
|
|
127
|
+
date :published_at, default: Date.today
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Extend with additional validations and methods
|
|
132
|
+
PostParams.post_schema do
|
|
133
|
+
validates :title, :content, presence: true, if: :published?
|
|
134
|
+
|
|
135
|
+
def published?
|
|
136
|
+
published_at.present?
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Now the validation will run conditionally
|
|
141
|
+
params = PostParams.new(id: 1)
|
|
142
|
+
params.valid? # => false (because published_at has default value, so published? returns true)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
You can also extend collection schemas:
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
class CommentParams < EasyParams::Base
|
|
149
|
+
each :comments, default: [{}, {}] do
|
|
150
|
+
integer :post_id
|
|
151
|
+
string :author
|
|
152
|
+
string :text
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Extend with additional attributes and validations
|
|
157
|
+
CommentParams.comments_schema do
|
|
158
|
+
string :author, default: 'Anonymous'
|
|
159
|
+
date :created_at, default: Date.today
|
|
160
|
+
validates :post_id, presence: true
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Default values are preserved and merged with input
|
|
164
|
+
params = CommentParams.new({})
|
|
165
|
+
params.comments.size # => 2
|
|
166
|
+
params.comments.first.author # => 'Anonymous'
|
|
167
|
+
params.comments.first.created_at # => Date.today
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Key Features:**
|
|
171
|
+
- **Preserves defaults**: Original default values are maintained when extending schemas
|
|
172
|
+
- **Runtime flexibility**: Add validations and methods by creating subclasses dynamically
|
|
173
|
+
- **Replaces parent**: The new subclass completely replaces the original schema class
|
|
174
|
+
- **Collection support**: Works with both `has` (struct) and `each` (collection) parameters
|
|
175
|
+
|
|
176
|
+
### Validation errors
|
|
177
|
+
|
|
83
178
|
```ruby
|
|
84
179
|
# app/params/api/v2/icqa/move_params.rb
|
|
85
180
|
class Api::V1::Carts::MoveParams < EasyParams::Base
|
|
@@ -97,7 +192,9 @@ class Api::V1::Carts::MoveParams < EasyParams::Base
|
|
|
97
192
|
end
|
|
98
193
|
end
|
|
99
194
|
```
|
|
100
|
-
|
|
195
|
+
|
|
196
|
+
Validation messages for nested attributes a set on top level and each nested object has `errors` set.
|
|
197
|
+
Errors will look like this.
|
|
101
198
|
```ruby
|
|
102
199
|
{
|
|
103
200
|
:"sections[0].id"=>an_instance_of(Array),
|
data/lib/easy_params/base.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module EasyParams
|
|
4
4
|
# Implements validations logic and nesting structures
|
|
5
|
-
class Base
|
|
5
|
+
class Base # rubocop:disable Metrics/ClassLength
|
|
6
6
|
include ActiveModel::Model
|
|
7
7
|
include EasyParams::Types::Struct
|
|
8
8
|
include EasyParams::Validation
|
|
@@ -19,6 +19,11 @@ module EasyParams
|
|
|
19
19
|
def inherited(subclass)
|
|
20
20
|
super
|
|
21
21
|
subclass.clone_schema(self)
|
|
22
|
+
subclass.clone_schemas(self)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def schemas
|
|
26
|
+
@schemas ||= {}
|
|
22
27
|
end
|
|
23
28
|
|
|
24
29
|
def name
|
|
@@ -41,7 +46,8 @@ module EasyParams
|
|
|
41
46
|
raise ArgumentError, "definition for attribute #{param_name.inspect} must be a subclass of EasyParams::Base"
|
|
42
47
|
end
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
handle_schema_definition(param_name, definition, collection: true, &block)
|
|
50
|
+
type = EasyParams::Types::Each.of(schemas[param_name].new)
|
|
45
51
|
type = customize_type(type, default, &normalize)
|
|
46
52
|
attribute(param_name, type)
|
|
47
53
|
end
|
|
@@ -52,7 +58,8 @@ module EasyParams
|
|
|
52
58
|
raise ArgumentError, "definition for attribute #{param_name.inspect} must be a subclass of EasyParams::Base"
|
|
53
59
|
end
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
handle_schema_definition(param_name, definition, &block)
|
|
62
|
+
type = schemas[param_name].new
|
|
56
63
|
type = customize_type(type, default, &normalize)
|
|
57
64
|
attribute(param_name, type)
|
|
58
65
|
end
|
|
@@ -68,6 +75,10 @@ module EasyParams
|
|
|
68
75
|
@schema = parent.schema.dup
|
|
69
76
|
end
|
|
70
77
|
|
|
78
|
+
def clone_schemas(parent)
|
|
79
|
+
@schemas = parent.schemas.dup
|
|
80
|
+
end
|
|
81
|
+
|
|
71
82
|
def define_type_method(type_name)
|
|
72
83
|
define_singleton_method(type_name) do |param_name, default: nil, normalize: nil, **validations|
|
|
73
84
|
validates param_name, **validations if validations.any?
|
|
@@ -83,6 +94,26 @@ module EasyParams
|
|
|
83
94
|
type = type.normalize(&normalize) if normalize
|
|
84
95
|
type
|
|
85
96
|
end
|
|
97
|
+
|
|
98
|
+
def handle_schema_definition(param_name, definition = nil, collection: false, &block)
|
|
99
|
+
schemas[param_name] = definition || Class.new(EasyParams::Base).tap { |c| c.class_eval(&block) }
|
|
100
|
+
define_schema_method(param_name, collection: collection)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def define_schema_method(param_name, collection: false)
|
|
104
|
+
define_singleton_method("#{param_name}_schema") do |&block|
|
|
105
|
+
default = schema[param_name].read_default
|
|
106
|
+
schemas[param_name] = Class.new(schemas[param_name]).tap { |c| c.class_eval(&block) }
|
|
107
|
+
type = create_schema_type(param_name, collection, default)
|
|
108
|
+
attribute(param_name, type)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def create_schema_type(param_name, collection, default)
|
|
113
|
+
type = schemas[param_name].new
|
|
114
|
+
type = EasyParams::Types::Each.of(type) if collection
|
|
115
|
+
customize_type(type, default)
|
|
116
|
+
end
|
|
86
117
|
end
|
|
87
118
|
|
|
88
119
|
def attributes
|
|
@@ -41,9 +41,8 @@ module EasyParams
|
|
|
41
41
|
|
|
42
42
|
# base interface for array of structs type
|
|
43
43
|
class StructsCollection < Collection
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
self.class.new(@title, @default, @normalize_proc, of: of_type)
|
|
44
|
+
def read_default
|
|
45
|
+
@default
|
|
47
46
|
end
|
|
48
47
|
end
|
|
49
48
|
end
|
data/lib/easy_params/version.rb
CHANGED
data/lib/easy_params.rb
CHANGED
|
@@ -39,20 +39,20 @@ module EasyParams
|
|
|
39
39
|
register_type :string, &:to_s
|
|
40
40
|
register_type(:decimal) { |v| v.to_f.to_d }
|
|
41
41
|
register_type(:bool) do |v|
|
|
42
|
-
BOOLEAN_MAP.fetch(v.to_s) { raise CoercionError }
|
|
42
|
+
v.is_a?(TrueClass) || v.is_a?(FalseClass) ? v : BOOLEAN_MAP.fetch(v.to_s) { raise CoercionError }
|
|
43
43
|
end
|
|
44
44
|
register_type(:date) do |v|
|
|
45
|
-
|
|
45
|
+
v.is_a?(Date) ? v : Date.parse(v)
|
|
46
46
|
rescue ArgumentError, RangeError
|
|
47
47
|
raise CoercionError, 'cannot be coerced'
|
|
48
48
|
end
|
|
49
49
|
register_type(:datetime) do |v|
|
|
50
|
-
|
|
50
|
+
v.is_a?(DateTime) ? v : DateTime.parse(v)
|
|
51
51
|
rescue ArgumentError
|
|
52
52
|
raise CoercionError, 'cannot be coerced'
|
|
53
53
|
end
|
|
54
54
|
register_type(:time) do |v|
|
|
55
|
-
|
|
55
|
+
v.is_a?(Time) ? v : Time.parse(v)
|
|
56
56
|
rescue ArgumentError
|
|
57
57
|
raise CoercionError, 'cannot be coerced'
|
|
58
58
|
end
|