easy_params 0.9.0 → 0.9.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: 56cdc3f7e00c381786f025e6aca73baacbb8b8e7cf02aaa6d37c163db2c8463e
4
- data.tar.gz: 531ef26595af187e646caa32a448c3c3b37b4d31f028d0202989424ea5761b90
3
+ metadata.gz: 2bee55f0854b77323d19e97acace58d7de0602aa1bb4500c19a0b9ea79f26013
4
+ data.tar.gz: 2587c8ae019b986041b712ddf9eb433666ff99efa7dcacbe1b4f6d2ae31ec66a
5
5
  SHA512:
6
- metadata.gz: 59d619a8301928dc576050eee95959edb97a5dbaac9a7179e0d2d698317236707b7715208e8274db8c0379a15fdb5d5035a6b445eb7bc7543583668dcda0ffcb
7
- data.tar.gz: 12a2e968a77f10af3c960bc57c6fc63b66c4dd2d1cbceff371114ac8f1c534e326ddf4b4365ccc4e826f979baa690b9661d54c1c9a3216bbdeac5e54f98248af
6
+ metadata.gz: b66f092c49e32afc330b5230184edad67af9c7ede2362befd80861978e90a22efe8dc86d9166121432416b9014fed2467654b294aa7c316dcf557ed13e987c1d
7
+ data.tar.gz: 45aaac0c0cb73909c1d75d9288fb1d3ab357a1a549295bebe160cbadb8cf0355b1bf1a112b14191fc2ca0d540b5a2667dd8b8b24ceedb01523e33086b6d9425d
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- easy_params (0.9.0)
4
+ easy_params (0.9.1)
5
5
  activemodel (>= 3.2)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -173,6 +173,77 @@ params.comments.first.created_at # => Date.today
173
173
  - **Replaces parent**: The new subclass completely replaces the original schema class
174
174
  - **Collection support**: Works with both `has` (struct) and `each` (collection) parameters
175
175
 
176
+ ### Composition and Owner Context
177
+
178
+ EasyParams supports composition through an owner relationship, allowing nested objects to access methods from their parent objects or an external owner object. This is particularly useful for conditional validations and accessing context from nested structures.
179
+
180
+ Every `EasyParams::Base` instance has an `owner` attribute that is automatically set for nested objects:
181
+ - Objects created with `has` get their parent as the owner
182
+ - Objects in collections created with `each` get the collection as their owner, and the collection gets the parent as its owner
183
+
184
+ You can access methods on the owner chain using the `owner_` prefix:
185
+
186
+ ```ruby
187
+ class Owner
188
+ def check_name?
189
+ true
190
+ end
191
+
192
+ def check_address_city?
193
+ true
194
+ end
195
+
196
+ def check_phone_number?
197
+ true
198
+ end
199
+ end
200
+
201
+ class UserParams < EasyParams::Base
202
+ integer :id
203
+ string :name, presence: { if: :owner_check_name? }
204
+
205
+ has :address do
206
+ string :street
207
+ string :city, presence: { if: :owner_check_address_city? }
208
+ string :state
209
+ string :zip
210
+ end
211
+
212
+ each :phones do
213
+ string :number, presence: { if: :owner_check_phone_number? }
214
+ string :type
215
+ end
216
+ end
217
+
218
+ # Use with an external owner object
219
+ owner = Owner.new
220
+ params = UserParams.new(
221
+ id: 1,
222
+ address: { street: '123 Main St', city: nil },
223
+ phones: [{ number: nil, type: 'home' }]
224
+ )
225
+ params.owner = owner
226
+
227
+ # Validations will use the owner's methods
228
+ params.valid? # => false
229
+ params.errors[:name] # => ["can't be blank"]
230
+ params.address.errors[:city] # => ["can't be blank"]
231
+ params.phones[0].errors[:number] # => ["can't be blank"]
232
+
233
+ # Owner relationships are automatically established
234
+ params.owner # => owner
235
+ params.address.owner # => params (parent)
236
+ params.phones.owner # => params (parent)
237
+ params.phones[0].owner # => params.phones (collection)
238
+ ```
239
+
240
+ **Key Features:**
241
+ - **Automatic owner setup**: Nested objects automatically get their parent as owner
242
+ - **Owner chain**: The `owner_` prefix searches up the owner chain to find methods
243
+ - **External owners**: Set an external object as owner to provide additional context
244
+ - **Conditional validations**: Use owner methods in validation conditions (`if:`, `unless:`)
245
+ - **Nested access**: Works at any nesting level - nested objects can access parent methods
246
+
176
247
  ### Validation errors
177
248
 
178
249
  ```ruby
@@ -52,7 +52,7 @@ module EasyParams
52
52
  raise ArgumentError, "definition for attribute #{param_name.inspect} must be a subclass of EasyParams::Base"
53
53
  end
54
54
 
55
- handle_schema_definition(param_name, definition, collection: true, &block)
55
+ handle_schema_definition(param_name, definition, &block)
56
56
  type = EasyParams::Types::Each.of(schemas[param_name].new)
57
57
  type = customize_type(type, default, &normalize)
58
58
  attribute(param_name, type)
@@ -101,24 +101,23 @@ module EasyParams
101
101
  type
102
102
  end
103
103
 
104
- def handle_schema_definition(param_name, definition = nil, collection: false, &block)
104
+ def handle_schema_definition(param_name, definition = nil, &block)
105
105
  schemas[param_name] = definition || Class.new(EasyParams::Base).tap { |c| c.class_eval(&block) }
106
- define_schema_method(param_name, collection: collection)
106
+ define_schema_method(param_name)
107
107
  end
108
108
 
109
- def define_schema_method(param_name, collection: false)
109
+ def define_schema_method(param_name)
110
110
  define_singleton_method("#{param_name}_schema") do |&block|
111
- default = schema[param_name].read_default
112
111
  schemas[param_name] = Class.new(schemas[param_name]).tap { |c| c.class_eval(&block) }
113
- type = create_schema_type(param_name, collection, default)
112
+ type = create_schema_type(param_name, schema[param_name])
114
113
  attribute(param_name, type)
115
114
  end
116
115
  end
117
116
 
118
- def create_schema_type(param_name, collection, default)
117
+ def create_schema_type(param_name, custom_type)
119
118
  type = schemas[param_name].new
120
- type = EasyParams::Types::Each.of(type) if collection
121
- customize_type(type, default)
119
+ type = EasyParams::Types::Each.of(type) if custom_type.is_a?(Types::StructsCollection)
120
+ customize_type(type, custom_type.read_default, &custom_type.normalize_proc)
122
121
  end
123
122
  end
124
123
 
@@ -21,7 +21,7 @@ module EasyParams
21
21
  return super unless name.to_s.start_with?('owner_')
22
22
 
23
23
  owner_method = name.to_s.sub('owner_', '').to_sym
24
- return super unless (handler = owners_chain.lazy.detect { |o| o.public_methods.include?(owner_method) })
24
+ return super unless (handler = owners_chain.lazy.detect { |o| o.respond_to?(owner_method) })
25
25
 
26
26
  handler.public_send(owner_method, *attrs, **kwargs, &block)
27
27
  end
@@ -37,7 +37,7 @@ module EasyParams
37
37
  def owners_chain
38
38
  @owners_chain ||= Enumerator.new do |y|
39
39
  obj = self
40
- y << obj = obj.owner while obj.public_methods.include?(:owner)
40
+ y << obj = obj.owner while obj.respond_to?(:owner)
41
41
  end
42
42
  end
43
43
  end
@@ -4,9 +4,7 @@ module EasyParams
4
4
  module Types
5
5
  # base interface for simple types
6
6
  class Generic
7
- def array?
8
- @title == :array
9
- end
7
+ attr_reader :normalize_proc
10
8
 
11
9
  def initialize(title, default = nil, normalize_proc = nil, &coerce_proc)
12
10
  @title = title
@@ -15,6 +13,10 @@ module EasyParams
15
13
  @normalize_proc = normalize_proc
16
14
  end
17
15
 
16
+ def array?
17
+ @title == :array
18
+ end
19
+
18
20
  def default(value)
19
21
  self.class.new(@title, value, @normalize_proc, &@coerce_proc)
20
22
  end
@@ -12,14 +12,26 @@ module EasyParams
12
12
  @default
13
13
  end
14
14
 
15
+ def normalize_proc
16
+ @normalize_proc
17
+ end
18
+
15
19
  def default(value)
16
20
  self.default = value
17
21
  self
18
22
  end
19
23
 
20
- def coerce(input)
21
- return if input.nil? && @default.nil?
22
- return self.class.new(@default) if input.nil? && @default.is_a?(Hash)
24
+ def normalize(&block)
25
+ @normalize_proc = block
26
+ self
27
+ end
28
+
29
+ def coerce(value)
30
+ return if value.nil? && @default.nil?
31
+
32
+ input = value || @default
33
+ input = @normalize_proc.call(input) if @normalize_proc
34
+ return self.class.new(input) if input.is_a?(Hash)
23
35
 
24
36
  self.class.new(input)
25
37
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EasyParams
4
- VERSION = '0.9.0'
4
+ VERSION = '0.9.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy_params
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrii Baran